Compare commits

...

83 Commits

Author SHA1 Message Date
Samuele Locatelli 8542b6c565 Merge branch 'develop' into new/dirSaveMgt 2020-09-12 17:25:04 +02:00
Samuele Locatelli 3c65bced53 fix letter case per xsd 2020-09-12 17:24:52 +02:00
Samuele Locatelli 95d29cc716 Aggunta files di config XML/XSD 2020-09-12 17:19:55 +02:00
Samuele Locatelli bcde0c8d86 Completato inserimento metodi x M156 2020-09-12 17:09:11 +02:00
Samuele Locatelli 76deabb93b Aggiunta preliminare metodi x gestione M156 2020-09-12 16:41:29 +02:00
Samuele Locatelli bfc99fc826 Merge branch 'develop' into new/dirSaveMgt 2020-09-10 17:26:53 +02:00
Samuele Locatelli cb28589f79 Gestione calcolo modifica parametri ricette + fix livedata save (tested) 2020-09-10 17:26:37 +02:00
Samuele Locatelli 8cae6edff2 start new rel 2020-09-10 15:33:45 +02:00
Samuele Locatelli 34a71b5784 Merge branch 'develop' into new/dirSaveMgt 2020-09-10 13:15:53 +02:00
Samuele Locatelli 455ddd660c new rel x SIM 2020-09-10 13:15:42 +02:00
Samuele Locatelli bbada3a929 update x fix calcolo tempo ciclo, calcolo durata, inizio lotto... 2020-09-10 13:15:29 +02:00
Samuele Locatelli 0a00ba3eae Merge remote-tracking branch 'origin/develop' into new/dirSaveMgt 2020-09-10 12:29:13 +02:00
Samuele Locatelli 7a3a068908 new rel 2020-09-10 12:21:13 +02:00
= 2a3de715da Merge remote-tracking branch 'CMS/develop' into develop 2020-09-10 10:12:47 +02:00
= 002b235d76 fix dashboar 2020-09-10 10:12:14 +02:00
= b135f017d5 modali da gantt 2020-09-10 09:52:02 +02:00
Samuele Locatelli 32e0c34945 rel ver x prod 2020-09-10 07:58:00 +02:00
Samuele Locatelli f32d0c0daf Merge remote-tracking branch 'origin/develop' into new/dirSaveMgt 2020-09-10 07:56:57 +02:00
NICOLA CARMINATI 014f63bd2b Added folder / file Manager to the Client 2020-09-09 18:03:56 +02:00
= a6e58365dd recipe note.. preview on save 2020-09-09 16:55:03 +02:00
= 7481d3bf28 print ricetta 2020-09-09 16:43:48 +02:00
= c036cd30e2 Merge remote-tracking branch 'CMS/develop' into develop 2020-09-09 15:51:52 +02:00
= 682efe1928 enabled fields visibility 2020-09-09 12:16:04 +02:00
= d511b49c64 enabled fields visibility 2020-09-09 12:15:54 +02:00
Samuele Locatelli bb7ef476ed new rel 2020-09-09 09:58:42 +02:00
Samuele Locatelli 393da8156b Aggiunto metodo x fornire note ad UI 2020-09-09 09:58:31 +02:00
Samuele Locatelli 575b74c676 Merge remote-tracking branch 'origin/develop' into new/dirSaveMgt 2020-09-09 08:16:52 +02:00
Samuele Locatelli 9f27a7b5ce Impostato default dirm da serverConfig/sharedPath 2020-09-09 08:16:43 +02:00
NICOLA CARMINATI 12ee118e72 Fix OnScreenKeyboard Option 2020-09-08 18:08:02 +02:00
= 00994f993b fix number 2020-09-08 17:31:50 +02:00
= 581c6d44fe fix sovrapposizione gant boxes 2020-09-08 15:04:32 +02:00
Samuele Locatelli a75edd650e start new rel 2020-09-08 14:56:50 +02:00
= eea8a2fa5d fix apertura blocchetti da categorie 2020-09-08 12:50:59 +02:00
= 14c9fb628b warmers 2020-09-08 12:40:25 +02:00
= 18530ea7b3 fix combo 2020-09-08 10:48:46 +02:00
= 04447282ea timeline gannt 2020-09-08 10:23:52 +02:00
= 582a4455e0 Merge remote-tracking branch 'CMS/develop' into develop 2020-09-08 10:09:28 +02:00
= 43fa8448d2 fix disegno stampo 2020-09-08 10:09:18 +02:00
Samuele Locatelli a6df5719f0 Merge remote-tracking branch 'origin/develop' into feature/prodMgmt 2020-09-08 09:49:07 +02:00
Samuele Locatelli d23f6fd4c5 new rel 2020-09-08 09:48:58 +02:00
= 91a554d616 utilities 2020-09-08 09:43:12 +02:00
= e96d97890f cancel della ricetta 2020-09-08 09:37:52 +02:00
= 42186c9509 fix remainging time negativo 2020-09-08 09:19:51 +02:00
= b0391855f5 fix numeric 2020-09-08 08:54:52 +02:00
= 305e2220f8 valueact 2020-09-08 08:48:31 +02:00
= a5d2323dea fix combo status 2020-09-08 08:41:17 +02:00
= 95db7bbdd9 Merge remote-tracking branch 'CMS/develop' into develop 2020-09-08 08:35:44 +02:00
= 345918cdaf valueAct 2020-09-08 08:35:19 +02:00
Samuele Locatelli 8bc9fc97c8 new rel 2020-09-07 13:55:09 +02:00
Samuele Locatelli cd5ea6c6cc Merge remote-tracking branch 'origin/develop' into feature/prodMgmt 2020-09-07 13:53:07 +02:00
= fb91158ee6 fix gant print & slider. 2020-09-07 12:52:53 +02:00
= 7b724b070f slider 2020-09-07 11:16:11 +02:00
= 7bb8602595 Merge remote-tracking branch 'CMS/develop' into develop 2020-09-07 10:32:55 +02:00
Samuele Locatelli 02b1b3b4c6 Merge branch 'feature/prodMgmt' into develop 2020-09-04 19:25:10 +02:00
Samuele Locatelli f499cdc203 new rel intermedia 71 2020-09-04 19:24:32 +02:00
Samuele Locatelli fa9db02e0e Aggiornamento gestione moduli x avere categorie + sub 2020-09-04 19:24:18 +02:00
Samuele Locatelli 136f3c40ff Update xml e validatore modBlock 2020-09-04 19:23:57 +02:00
= 0e02b0ca3f fixes 2020-09-04 17:14:15 +02:00
= 913834a34d Merge remote-tracking branch 'CMS/develop' into develop 2020-09-04 15:14:54 +02:00
= 6b0d5e2c03 fix generali e gestione produzione 2020-09-04 15:14:32 +02:00
Samuele Locatelli 3ead2b7283 Merge branch 'feature/prodMgmt' into develop 2020-09-04 11:52:21 +02:00
Samuele Locatelli 66ba44868e Update x nuova gest codici errore in core library 2020-09-04 11:46:30 +02:00
Samuele Locatelli 529266b57b Merge branch 'feature/prodMgmt' into develop 2020-09-04 10:45:54 +02:00
Samuele Locatelli e1280c193f eliminati commenti + aggiornamento readme, testato bounce ricetta 2020-09-04 10:45:41 +02:00
Samuele Locatelli 77cec0160a rimesso metodo x set AUTO + metodo x start prod full 2020-09-04 09:32:17 +02:00
Samuele Locatelli f7234dd34b new rel 2020-09-04 09:29:30 +02:00
Samuele Locatelli 4c7ad000db rimesso softkey x reset 2020-09-04 09:24:06 +02:00
Samuele Locatelli 140afc4539 Merge branch 'feature/prodMgmt' into develop 2020-09-03 17:56:52 +02:00
Samuele Locatelli 699ccfbfba Commentata gest cicli warmup come richiesto 2020-09-03 17:56:44 +02:00
Samuele Locatelli 3877cb7843 new rel 2020-09-03 12:04:11 +02:00
Samuele Locatelli 80e6192e46 Conf parameters per gestione scrittura recipe 2020-09-03 12:03:59 +02:00
Samuele Locatelli 2786c8e6a8 Merge branch 'develop' into feature/prodMgmt 2020-09-03 11:19:07 +02:00
Samuele Locatelli efbfd857f6 new rel 2020-09-03 11:18:55 +02:00
Samuele Locatelli 3968f72061 Gestione cicli riscaldo in WRITE sul PLC 2020-09-03 11:18:50 +02:00
Samuele Locatelli 88e78736f0 Merge branch 'feature/prodMgmt' into develop 2020-09-02 18:23:09 +02:00
Samuele Locatelli a362829256 Update gestione nuovo dato scrap (metodo x salvataggio...) 2020-09-02 18:21:11 +02:00
Samuele Locatelli 43abdd203b update note x migrations 2020-09-02 18:20:59 +02:00
Samuele Locatelli 74e51a4156 Update modello dati x SCRAP parts 2020-09-02 18:00:51 +02:00
Samuele Locatelli 52621f83e8 new sprint 2020-09-02 18:00:36 +02:00
= 9be02d4666 dashboard & toggle.. 2020-09-02 17:52:54 +02:00
= 2f2fc02730 clock & dashboard 2020-09-02 15:44:10 +02:00
= cccd8f2c36 gantt printing 2020-09-02 15:15:41 +02:00
= 71a1333c12 gantt print 2020-09-01 16:52:24 +02:00
113 changed files with 2825 additions and 736 deletions
+92 -7
View File
@@ -38,12 +38,12 @@ namespace Active_Client.Browser_Tools
private static readonly string[] _validExtensions = {".json", ".rcp", ".tpl" };
//private static readonly string[] _validExtensions = { "", ".txt", ".cnc", ".cn", ".cno", ".ini", ".mpf", ".spf", ".tap", ".anc", ".iso" };
private static readonly string[] _validImages = { ".jpg", ".jpeg", ".png" };
private static readonly string[] _validImages = { ".jpg", ".jpeg", ".png", ".svg" };
private static string jobPath = "";
private static Dictionary<string, IntPtr> _editorOpened = new Dictionary<string, IntPtr>();
private static EditorVar _currentEditorObject = new EditorVar();
public static string RECENT_FOLDER_KEY = "RECENT";
private const string THERMO_RECIPE_PATH = @"C:\CMS\Recipes";
private const string THERMO_RECIPE_PATH = @"C:\CMS\Recipe";
public static FileSystemWatcher watcher = null;
public static DateTime _lastTimeFileWatcherEventRaised = DateTime.Now;
@@ -80,6 +80,11 @@ namespace Active_Client.Browser_Tools
AddFunction("getFileList").Execute += getFileList;
AddFunction("getProgramInfo").Execute += getProgramInfo;
AddFunction("editProgram").Execute += editProgram;
AddFunction("deleteFile").Execute += deleteFile;
AddFunction("deleteFolder").Execute += deleteFolder;
AddFunction("createFolder").Execute += createFolder;
AddFunction("uploadAndActivateProgram").Execute += uploadAndActivateProgram;
AddFunction("uploadAndAddToQueue").Execute += uploadAndAddToQueue;
@@ -360,6 +365,7 @@ namespace Active_Client.Browser_Tools
List<Drive> drivelist = new List<Drive>();
// USB & HD Drives
/*
foreach (var drive in DriveInfo.GetDrives())
{
if (drive.IsReady)
@@ -376,7 +382,7 @@ namespace Active_Client.Browser_Tools
}
}
}
// Desktop folder
drivelist.Add(new Drive()
{
@@ -384,6 +390,7 @@ namespace Active_Client.Browser_Tools
Path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\",
Type = "SPFO"
});
*/
if (Directory.Exists(THERMO_RECIPE_PATH))
{
@@ -394,7 +401,7 @@ namespace Active_Client.Browser_Tools
Type = "SPFO"
});
}
/*
try
{
// Network Folders
@@ -416,7 +423,7 @@ namespace Active_Client.Browser_Tools
catch (Exception ex)
{
}
}*/
e.SetReturnValue(JsonConvert.SerializeObject(drivelist));
}
@@ -485,6 +492,85 @@ namespace Active_Client.Browser_Tools
e.SetReturnValue(JsonConvert.SerializeObject(filelist));
}
public void deleteFile(object sender, CfrV8HandlerExecuteEventArgs e)
{
if (e.Arguments.Count() == 0)
{
e.SetReturnValue(JsonConvert.SerializeObject(new ErrorContainer("error_arguments_not_ok")));
return;
}
// Get path
string p = e.Arguments[0].StringValue;
FileAttributes attr = File.GetAttributes(p);
if (!File.Exists(p) || attr.HasFlag(FileAttributes.Directory))
{
e.SetReturnValue(JsonConvert.SerializeObject(new ErrorContainer("file_not_found")));
return;
}
if (attr.HasFlag(FileAttributes.ReadOnly))
{
e.SetReturnValue(JsonConvert.SerializeObject(new ErrorContainer("file_not_editable")));
return;
}
try
{
File.Delete(p);
}
catch(Exception ex)
{
e.SetReturnValue(JsonConvert.SerializeObject(new ErrorContainer("cannot_delete_file")));
}
}
public void deleteFolder(object sender, CfrV8HandlerExecuteEventArgs e)
{
if (e.Arguments.Count() == 0)
{
e.SetReturnValue(JsonConvert.SerializeObject(new ErrorContainer("error_arguments_not_ok")));
return;
}
// Get path
string p = e.Arguments[0].StringValue;
FileAttributes attr = File.GetAttributes(p);
if (!Directory.Exists(p) || !attr.HasFlag(FileAttributes.Directory))
{
e.SetReturnValue(JsonConvert.SerializeObject(new ErrorContainer("directory_not_found")));
return;
}
if (attr.HasFlag(FileAttributes.ReadOnly))
{
e.SetReturnValue(JsonConvert.SerializeObject(new ErrorContainer("directory_not_editable")));
return;
}
try
{
Directory.Delete(p,true);
}
catch (Exception ex)
{
e.SetReturnValue(JsonConvert.SerializeObject(new ErrorContainer("cannot_delete_directory")));
}
}
public void createFolder(object sender, CfrV8HandlerExecuteEventArgs e)
{
if (e.Arguments.Count() == 0)
{
e.SetReturnValue(JsonConvert.SerializeObject(new ErrorContainer("error_arguments_not_ok")));
return;
}
string path = e.Arguments[0].StringValue;
try
{
Directory.CreateDirectory(path);
}
catch (Exception ex)
{
e.SetReturnValue(JsonConvert.SerializeObject(new ErrorContainer("cannot_delete_directory")));
}
}
// Upload and activate the program
public async void uploadAndActivateProgram(object sender, CfrV8HandlerExecuteEventArgs e)
{
@@ -671,8 +757,7 @@ namespace Active_Client.Browser_Tools
// Read info of a file
public void getProgramInfo(object sender, CfrV8HandlerExecuteEventArgs e)
{
string line, imagePath, imageDirectory;
int counter = 0;
string imagePath, imageDirectory;
if (e.Arguments.Count() == 0)
{
+2 -2
View File
@@ -165,7 +165,7 @@ namespace Active_Client.View
public void sendClose()
{
//Close Virtual Keyboard Runtime
if (Config.ClientConfig.ShowVirtualKeyboard && Environment.OSVersion.Version.Major < 10)
if (Config.ClientConfig.ShowVirtualKeyboard)
NcWindow.closeVirtualKeyboard();
//Close the NC HMI && Stop Following Nc
@@ -259,7 +259,7 @@ namespace Active_Client.View
Browser.DisplayHandler.OnConsoleMessage += BrowserConsoleMessage;
Browser.DownloadHandler.OnBeforeDownload += BeforeDownload;
//Filter only < Win_10 Platform
if (Config.ClientConfig.ShowVirtualKeyboard && Environment.OSVersion.Version.Major < 10)
if (Config.ClientConfig.ShowVirtualKeyboard)
ChromiumWebBrowser.RemoteProcessCreated += (e) => { e.RenderProcessHandler.OnFocusedNodeChanged += BrowserNodeChanged; };
}
+2 -2
View File
@@ -1047,7 +1047,7 @@ namespace Active_Client.View
if (!IsIconic(MainViewHandle))
{
//Show Virtual keyboard
if (Config.ClientConfig.ShowVirtualKeyboard && Environment.OSVersion.Version.Major < 10)
if (Config.ClientConfig.ShowVirtualKeyboard)
reOpenVirtualKeyboard();
}
}
@@ -1069,7 +1069,7 @@ namespace Active_Client.View
//SetForegroundWindow(hwnd);
//Hide Virtual keyboard
if (Config.ClientConfig.ShowVirtualKeyboard && Environment.OSVersion.Version.Major < 10 && KeyboardPID != 0 && ActualPID != KeyboardPID)
if (Config.ClientConfig.ShowVirtualKeyboard && KeyboardPID != 0 && ActualPID != KeyboardPID)
closeVirtualKeyboard();
}
+15 -2
View File
@@ -5,11 +5,24 @@
## Ambiente sviluppo e simulazione
## Procedura udpate DB
In caso di update del modello DB, seguendo questa guida (https://www.entityframeworktutorial.net/efcore/entity-framework-core-migration.aspx#:~:text=Adding%20a%20Migration,-At%20the%20very&text=So%2C%20firstly%2C%20you%20need%20to,command%20to%20add%20a%20migration.&text=If%20you%20are%20using%20dotnet,Interface%2C%20execute%20the%20following%20command.)
* si modifica lato classe il modello
* si apre il PM Nuget,s elezionando il progetto DB (che contiene le migrations)
* si da il comando di migrazione con un testo descrittivo, tipo
add-migration MyFirstMigration
* si può poi aggiornare il DB manualmente (o all'avvio del sw) con il comando
Update-Database
## Procedura Riavvio su SIM
Step come indicati da M.Carissoni:
* Dai un paio di ResetSK
* fai cicloReset
* mettere macchina in MANUAL
* Dai un paio di ResetSK (prima softkey! oppure sul pannello siemens)
* fai cicloReset (softkey)
* parcheggio macchina da GANT (fino a che si spegne)
* quando si spegne ciclo reset auto
* Inizia a lampeggiare start e lo clicchi e parte
* Quando si spegne cicloReset fai cicloAuto
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="inputsOperator">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element name="realValueModal" type="valuesType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="showValModal" type="showValType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="buttonsListModal" type="buttonsType" minOccurs="0" maxOccurs="unbounded"/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:complexType name="valuesType">
<xs:all>
<xs:element name="id" minOccurs='1' maxOccurs='1'/>
<xs:element name="title" type="translatedText" minOccurs='1' maxOccurs='1'/>
</xs:all>
</xs:complexType>
<xs:complexType name="showValType">
<xs:all>
<xs:element name="id" minOccurs='1' maxOccurs='1'/>
<xs:element name="title" type="translatedText" minOccurs='1' maxOccurs='1'/>
<xs:element name="buttons">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element name="button">
<xs:complexType>
<xs:all>
<xs:element name="value" minOccurs="1" maxOccurs="1" type="xs:int"></xs:element>
<xs:element name="title" type="translatedText" minOccurs='1' maxOccurs='1'/>
</xs:all>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:all>
</xs:complexType>
<xs:complexType name="buttonsType">
<xs:all>
<xs:element name="id" minOccurs='1' maxOccurs='1'/>
<xs:element name="title" type="translatedText" minOccurs='1' maxOccurs='1'/>
<xs:element name="buttons">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element name="button">
<xs:complexType>
<xs:all>
<xs:element name="value" minOccurs="1" maxOccurs="1" type="xs:int"></xs:element>
<xs:element name="title" type="translatedText" minOccurs='1' maxOccurs='1'/>
</xs:all>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:all>
</xs:complexType>
<!-- Translations field Type -->
<xs:complexType name="translatedText">
<xs:sequence>
<xs:element name="lang" type="langType" minOccurs="0" maxOccurs="unbounded">
</xs:element>
</xs:sequence>
</xs:complexType>
<!-- lang field -->
<xs:complexType name="langType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="langKey" use="required" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<inputsOperator>
<buttonsListModal>
<id>1</id>
<title>
<lang langKey="it">Hai rimosso manualmente anche il pezzo lavorato ?</lang>
<lang langKey="en">Have you also manually removed the workpiece ?</lang>
</title>
<buttons>
<button>
<value>0</value>
<title>
<lang langKey="it">No</lang>
<lang langKey="en">No</lang>
</title>
</button>
<button>
<value>1</value>
<title>
<lang langKey="it">Si</lang>
<lang langKey="en">Yes</lang>
</title>
</button>
</buttons>
</buttonsListModal>
<realValueModal>
<id>10</id>
<title>
<lang langKey="en">External water</lang>
<lang langKey="it">Acqua esterna</lang>
</title>
</realValueModal>
<realValueModal>
<id>11</id>
<title>
<lang langKey="en">External water</lang>
<lang langKey="it">Acqua esterna</lang>
</title>
</realValueModal>
<buttonsListModal>
<id>6</id>
<title>
<lang langKey="en">External water</lang>
<lang langKey="it">Acqua esterna</lang>
</title>
<buttons>
<button>
<value>3</value>
<title>
<lang langKey="en">External water</lang>
<lang langKey="it">Acqua esterna</lang>
</title>
</button>
<button>
<value>4</value>
<title>
<lang langKey="en">External water</lang>
<lang langKey="it">Acqua esterna</lang>
</title>
</button>
</buttons>
</buttonsListModal>
</inputsOperator>
@@ -71,6 +71,9 @@
<idParam>80</idParam>
<showDelay>true</showDelay>
<priority>3</priority>
<category>Pyrometer</category>
<subCategory_1>Pyrometer</subCategory_1>
<subCategory_2></subCategory_2>
</block>
<block>
<id>9</id>
@@ -116,6 +119,9 @@
<idParam>99</idParam>
<showDelay>true</showDelay>
<priority>2</priority>
<category>Drawing</category>
<subCategory_1></subCategory_1>
<subCategory_2></subCategory_2>
</block>
<block>
<id>14</id>
@@ -152,6 +158,9 @@
<idParam>139</idParam>
<showDelay>true</showDelay>
<priority>4</priority>
<category>Cooling</category>
<subCategory_1>Pyrometer</subCategory_1>
<subCategory_2></subCategory_2>
</block>
<block>
<id>19</id>
@@ -16,6 +16,9 @@
<xs:element name="priority" type="xs:int" />
<xs:element name="scaleFactor" type="xs:int" minOccurs="0" />
<xs:element name="numDec" type="xs:int" minOccurs="0" />
<xs:element name="category" type="param_type" minOccurs="0" />
<xs:element name="subCategory_1" type="xs:string" minOccurs="0" />
<xs:element name="subCategory_2" type="xs:string" minOccurs="0" />
</xs:all>
</xs:complexType>
</xs:element>
@@ -23,6 +26,23 @@
</xs:complexType>
</xs:element>
<!-- Head Type -->
<xs:simpleType name="param_type" final="restriction">
<xs:restriction base="xs:string">
<xs:enumeration value="General" />
<xs:enumeration value="Positions" />
<xs:enumeration value="Cycle"/>
<xs:enumeration value="Heats"/>
<xs:enumeration value="Pyrometer"/>
<xs:enumeration value="Drawing"/>
<xs:enumeration value="UpperPlate"/>
<xs:enumeration value="Cooling"/>
<xs:enumeration value="Vacuum"/>
<xs:enumeration value="Extraction"/>
<xs:enumeration value="Options"/>
</xs:restriction>
</xs:simpleType>
<!-- Language Type -->
<xs:complexType name="langType">
<xs:simpleContent>
+1 -1
View File
@@ -6,7 +6,7 @@
<ncIpAddress>192.168.0.102</ncIpAddress>
<ncPort>102</ncPort>
<machineModel>Thermo 2020</machineModel>
<sharedPath>C:\PartPrg\</sharedPath>
<sharedPath>C:\CMS\Recipes\</sharedPath>
<sharedName>//PARTPRG:/</sharedName>
<installationDate>01/06/2020</installationDate>
<mgiOption>false</mgiOption>
@@ -2,7 +2,7 @@
<userSoftKeys>
<softKey_procedure>
<active>false</active>
<active>true</active>
<category>1</category>
<operatorConfirmationNeeded>false</operatorConfirmationNeeded>
<plcId>1</plcId>
+1 -2
View File
@@ -51,10 +51,9 @@ namespace Thermo.Active.Config
public static List<ScadaSchemaModel> SubscribedScada = new List<ScadaSchemaModel>();
public static List<string> MacrosConfig;
public static List<InputOperatorConfigModel> InputsOperatorConfig;
public static string CMSMainProgramContent;
// Thermo
public static List<ThermoProdConfigModel> ThermoProdConfig;
public static List<RecipeConfigModel> RecipeConfig;
+46 -2
View File
@@ -41,6 +41,7 @@ namespace Thermo.Active.Config
// ReadCMSConnectConfig();
ReadMacros();
ReadScadaFile();
ReadM156();
}
catch (XmlException ex)
{
@@ -254,6 +255,47 @@ namespace Thermo.Active.Config
}
}
private static void ReadM156()
{
// Get Areas file handler
XDocument xmlConfigFile = GetXmlHandlerWithValidator(M156_CONFIG_SCHEMA_PATH, M156_CONFIG_PATH);
InputsOperatorConfig = xmlConfigFile
.Descendants("inputsOperator")
.Elements()
.Select(x => new InputOperatorConfigModel()
{
Id = Convert.ToInt32(x.Element("id").Value),
Messages = x.Element("title").Elements().ToDictionary( // Read localized names and convert into a dictionary
y => y.Attribute("langKey").Value, y => y.Value
),
Buttons = x.Element("buttons")?.Elements().ToDictionary( // Read buttons data and convert into a dictionary
y => Convert.ToByte(y.Element("value").Value),
y => y.Element("title").Elements().ToDictionary( // Read localized names and convert into a dictionary
z => z.Attribute("langKey").Value,
z => z.Value
)
),
Type = GetInputOperatoType(x.Name.ToString())
})
.ToList();
}
public static string GetInputOperatoType(string tagName)
{
switch (tagName)
{
case "modalValue":
return "REAL";
case "buttonsListModal":
return "MULTIPLE_BUTTONS";
case "showValModal":
return "SHOW_VAL";
default:
return "REAL";
}
}
#region Read config from file from configuration
@@ -628,7 +670,6 @@ namespace Thermo.Active.Config
NumDec = Convert.ToInt32(x.Element("numDec").Value),
MinVal = Convert.ToInt32(x.Element("minVal").Value),
MaxVal = Convert.ToInt32(x.Element("maxVal").Value),
})
.ToList();
}
@@ -654,7 +695,10 @@ namespace Thermo.Active.Config
Priority = Convert.ToInt16(x.Element("priority").Value),
// attributi presi da default se NON presenti...
ScaleFactor = x.Element("scaleFactor") != null ? Convert.ToInt16(x.Element("scaleFactor").Value) : 1000,
NumDec = x.Element("numDec") != null ? Convert.ToInt16(x.Element("numDec").Value) : 1
NumDec = x.Element("numDec") != null ? Convert.ToInt16(x.Element("numDec").Value) : 1,
Category = x.Element("category") != null ? x.Element("category").Value : "",
SubCategory_1 = x.Element("subCategory_1") != null ? x.Element("subCategory_1").Value : "",
SubCategory_2 = x.Element("subCategory_2") != null ? x.Element("subCategory_2").Value : ""
})
.ToList();
}
@@ -51,6 +51,9 @@
<Content Include="Config\axesConfig.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Config\inputOperatorConfig.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Config\macrosConfig.xml">
<SubType>Designer</SubType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -200,6 +203,10 @@
</ItemGroup>
<ItemGroup />
<ItemGroup>
<EmbeddedResource Include="Config\inputOperatorConfigValidator.xsd">
<SubType>Designer</SubType>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<None Include="Config\Recipes\template.tpl">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
+48 -2
View File
@@ -810,8 +810,6 @@ public static class ThreadsFunctions
MessageServices.Current.Publish(SEND_THERMO_RECIPE_FULL, null, currRecipe);
// FIXME TODO verificare come ridurre chiamate
// ora gestisco la overview!
libraryError = ncAdapter.GetRecipeOverview(out Dictionary<RecipeSection, RecipeCatStatus> currOverview);
if (libraryError.IsError())
@@ -959,6 +957,54 @@ public static class ThreadsFunctions
ncAdapter.Dispose();
}
}
public static void ReadMComandsData()
{
NcAdapter ncAdapter = new NcAdapter();
Stopwatch sw = new Stopwatch();
try
{
// Try connection
CmsError libraryError = ncAdapter.Connect();
if (libraryError.errorCode != 0)
ManageLibraryError(libraryError);
while (true)
{
sw.Restart();
if (ncAdapter.numericalControl.NC_IsConnected())
{
// solo x S7Net...
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
{
libraryError = ncAdapter.GetM156Data(out List<DTOM156InputModel> m156Data);
if (libraryError.IsError())
ManageLibraryError(libraryError);
else
MessageServices.Current.Publish(SEND_M156_DATA, null, m156Data);
}
}
else
RestoreConnection();
sw.Stop();
//Update thread timer
UpdateStat(MethodBase.GetCurrentMethod().Name, sw.ElapsedMilliseconds);
// Wait
Thread.Sleep(CalcSleepTime(200, (int)sw.ElapsedMilliseconds));
}
}
catch (ThreadAbortException)
{
ncAdapter.Dispose();
}
}
public static void ReadM154Data()
{
NcAdapter ncAdapter = new NcAdapter();
+2
View File
@@ -35,7 +35,9 @@ namespace Thermo.Active.Core
ThreadsFunctions.ReadAreaData,
ThreadsFunctions.ReadModulesData,
ThreadsFunctions.ReadScadaData,
ThreadsFunctions.ReadMComandsData,
ThreadsFunctions.ReadM154Data // levare?
};
private static Action ThreadSetupCmsConnect = ThreadsFunctions.SetupCmsConnect;
@@ -67,8 +67,9 @@ namespace Thermo.Active.Database.Controllers
/// <param name="VacuumReadVal"></param>
/// <param name="MouldEnergyOUT"></param>
/// <param name="MouldEnergyIN"></param>
/// <param name="IsScrap"></param>
/// <returns></returns>
public ProdInfoModel Create(short NumTarget, short NumDone, int TimeWarm, int TimeVent, int TimeVacuum, int TimeCycleGross, int TimeCycleNet, double MaterialTempEndWarm, double MaterialTempEndVent, double MoldTemp, double VacuumReadVal, double MouldEnergyOUT, double MouldEnergyIN)
public ProdInfoModel Create(short NumTarget, short NumDone, int TimeWarm, int TimeVent, int TimeVacuum, int TimeCycleGross, int TimeCycleNet, double MaterialTempEndWarm, double MaterialTempEndVent, double MoldTemp, double VacuumReadVal, double MouldEnergyOUT, double MouldEnergyIN, bool IsScrap)
{
// Create database machine model
ProdInfoModel prodData = new ProdInfoModel()
@@ -86,7 +87,8 @@ namespace Thermo.Active.Database.Controllers
MoldTemp = MoldTemp,
VacuumReadVal = VacuumReadVal,
MouldEnergyOUT = MouldEnergyOUT,
MouldEnergyIN = MouldEnergyIN
MouldEnergyIN = MouldEnergyIN,
IsScrap = IsScrap
};
try
{
@@ -100,6 +102,33 @@ namespace Thermo.Active.Database.Controllers
return prodData;
}
/// <summary>
/// Process table and set as scrap by num value
/// </summary>
/// <param name="maxKeep"></param>
/// <returns></returns>
public bool SetScrap(int num, bool isScrap)
{
bool answ = false;
var currRecord = dbCtx
.ProdInfo
.Where(x => x.NumDone == num)
.SingleOrDefault();
try
{
if (currRecord != null)
{
currRecord.IsScrap = isScrap;
}
// save!
dbCtx.SaveChanges();
answ = true;
}
catch
{ }
return answ;
}
/// <summary>
/// Process table and keep only maxKeep most recent ones
@@ -0,0 +1,29 @@
// <auto-generated />
namespace Thermo.Active.Database.Migrations
{
using System.CodeDom.Compiler;
using System.Data.Entity.Migrations;
using System.Data.Entity.Migrations.Infrastructure;
using System.Resources;
[GeneratedCode("EntityFramework.Migrations", "6.2.0-61023")]
public sealed partial class AddedScrapPartMgmt : IMigrationMetadata
{
private readonly ResourceManager Resources = new ResourceManager(typeof(AddedScrapPartMgmt));
string IMigrationMetadata.Id
{
get { return "202009021558544_AddedScrapPartMgmt"; }
}
string IMigrationMetadata.Source
{
get { return null; }
}
string IMigrationMetadata.Target
{
get { return Resources.GetString("Target"); }
}
}
}
@@ -0,0 +1,18 @@
namespace Thermo.Active.Database.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class AddedScrapPartMgmt : DbMigration
{
public override void Up()
{
AddColumn("dbo.ProdInfo", "IsScrap", c => c.Boolean(nullable: false));
}
public override void Down()
{
DropColumn("dbo.ProdInfo", "IsScrap");
}
}
}
File diff suppressed because one or more lines are too long
@@ -131,6 +131,10 @@
<Compile Include="Migrations\202006170558519_AddedProdInfoModel.Designer.cs">
<DependentUpon>202006170558519_AddedProdInfoModel.cs</DependentUpon>
</Compile>
<Compile Include="Migrations\202009021558544_AddedScrapPartMgmt.cs" />
<Compile Include="Migrations\202009021558544_AddedScrapPartMgmt.Designer.cs">
<DependentUpon>202009021558544_AddedScrapPartMgmt.cs</DependentUpon>
</Compile>
<Compile Include="Migrations\Configuration.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Redis\redUtil.cs" />
@@ -173,6 +177,9 @@
<EmbeddedResource Include="Migrations\202006170558519_AddedProdInfoModel.resx">
<DependentUpon>202006170558519_AddedProdInfoModel.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Migrations\202009021558544_AddedScrapPartMgmt.resx">
<DependentUpon>202009021558544_AddedScrapPartMgmt.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Thermo.Active.Model.ConfigModels
{
public class InputOperatorConfigModel
{
public int Id { get; set; }
public Dictionary<string, string> Messages { get; set; }
public Dictionary<byte, Dictionary<string, string>> Buttons { get; set; }
public string Type { get; set; }
}
}
@@ -14,5 +14,8 @@ namespace Thermo.Active.Model.ConfigModels
public int Priority { get; set; }
public int ScaleFactor { get; set; } = 1000;
public int NumDec { get; set; } = 1;
public string Category { get; set; }
public string SubCategory_1 { get; set; }
public string SubCategory_2 { get; set; }
}
}
+6 -3
View File
@@ -222,9 +222,8 @@ namespace Thermo.Active.Model
public const int numRecProdPanelGraph = 30;
public const string CONFIG_DIRECTORY = "Config\\";
public const string RECIPE_DIRECTORY = "Recipes\\";
public const string RECIPE_TEMPLATE_PATH = CONFIG_DIRECTORY + RECIPE_DIRECTORY + "template.tpl";
public const string LIVE_RECIPE_PATH = TEMP_FOLDER + RECIPE_DIRECTORY + "current.rcp";
public const string RECIPE_TEMPLATE_PATH = CONFIG_DIRECTORY + "Recipes\\template.tpl";
public const string LIVE_RECIPE_PATH = TEMP_FOLDER + "Recipes\\current.rcp";
public const string RESOURCE_DIRECTORY = @"Thermo.Active.Config.Config.";
public const string SERVER_CONFIG_SCHEMA_PATH = RESOURCE_DIRECTORY + @"serverConfigValidator.xsd";
public const string SERVER_CONFIG_PATH = CONFIG_DIRECTORY + "serverConfig.xml";
@@ -232,6 +231,9 @@ namespace Thermo.Active.Model
public const string AREAS_CONFIG_SCHEMA_PATH = RESOURCE_DIRECTORY + "areasConfigValidator.xsd";
public const string AREAS_CONFIG_PATH = CONFIG_DIRECTORY + "areasConfig.xml";
public const string M156_CONFIG_SCHEMA_PATH = RESOURCE_DIRECTORY + "inputOperatorConfigValidator.xsd";
public const string M156_CONFIG_PATH = CONFIG_DIRECTORY + "inputOperatorConfig.xml";
public const string MAINTENANCES_CONFIG_SCHEMA_PATH = RESOURCE_DIRECTORY + "maintenancesConfigValidator.xsd";
public const string CUSTOMER_CONTACTS_CONFIG_SCHEMA_PATH = RESOURCE_DIRECTORY + "customerContactConfigValidator.xsd";
public const string MAINTENANCES_CONFIG_PATH = CONFIG_DIRECTORY + "maintenancesConfig.xml";
@@ -309,6 +311,7 @@ namespace Thermo.Active.Model
public const string SEND_ACTIVE_PROGRAM_DATA = "SEND_ACTIVE_PROGRAM_DATA";
public const string SEND_QUEUE_DATA = "SEND_QUEUE_DATA";
public const string SEND_M155_DATA = "SEND_M155_DATA";
public const string SEND_M156_DATA = "SEND_M156_DATA";
public const string SEND_SCADA_DATA = "SEND_SCADA_DATA";
// MVVM Messages for Thermo active specs
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static CMS_CORE_Library.Models.DataStructures;
namespace Thermo.Active.Model.DTOModels
{
public class DTOM156InputModel : M156InputIsNeededModel
{
public Dictionary<byte, string> Buttons;
public string Type;
public bool isM156 = true;
public override bool Equals(object obj)
{
if (!(obj is DTOM156InputModel item))
return false;
if (Process != item.Process)
return false;
if (Type != item.Type)
return false;
return true;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
}
@@ -24,6 +24,9 @@ namespace Thermo.Active.Model.DTOModels.ThModules
public bool Running { get; set; } = false;
public bool HasError { get; set; } = false;
public bool Terminated { get; set; } = false;
public string Category { get; set; } = "";
public string SubCategory_1 { get; set; } = "";
public string SubCategory_2 { get; set; } = "";
public override bool Equals(object obj)
@@ -67,6 +70,12 @@ namespace Thermo.Active.Model.DTOModels.ThModules
return false;
if (Terminated != item.Terminated)
return false;
if (Category != item.Category)
return false;
if (SubCategory_1 != item.SubCategory_1)
return false;
if (SubCategory_2 != item.SubCategory_2)
return false;
return true;
}
@@ -25,6 +25,7 @@ namespace Thermo.Active.Model.DTOModels.ThProd
public double VacuumReadVal { get; set; } = 0;
public double MouldEnergyOUT { get; set; } = 0;
public double MouldEnergyIN { get; set; } = 0;
public bool IsScrap { get; set; } = false;
public override bool Equals(object obj)
{
@@ -60,6 +61,8 @@ namespace Thermo.Active.Model.DTOModels.ThProd
return false;
if (MouldEnergyIN != item.MouldEnergyIN)
return false;
if (IsScrap != item.IsScrap)
return false;
return true;
}
@@ -88,6 +91,7 @@ namespace Thermo.Active.Model.DTOModels.ThProd
this.VacuumReadVal = pimRawData.VacuumReadVal;
this.MouldEnergyIN = pimRawData.MouldEnergyIN;
this.MouldEnergyOUT = pimRawData.MouldEnergyOUT;
this.IsScrap = pimRawData.IsScrap;
}
}
}
@@ -12,6 +12,10 @@ namespace Thermo.Active.Model.DTOModels.ThRecipe
/// </summary>
public string RecipeName = "current.json";
/// <summary>
/// Current DIR of loaded recipe
/// </summary>
public string RecipeDir = "";
/// <summary>
/// User that made last save
/// </summary>
public string UserSave = "";
@@ -35,7 +39,9 @@ namespace Thermo.Active.Model.DTOModels.ThRecipe
/// Note ricetta
/// </summary>
public string recipeNotes = "";
/// <summary>
/// Verifica se sia cambiata da versione letta
/// </summary>
public bool hasChanged = false;
}
}
@@ -42,6 +42,8 @@ namespace Thermo.Active.Model.DatabaseModels
public double MouldEnergyOUT { get; set; }
[Column("MouldEnergyIN")]
public double MouldEnergyIN { get; set; }
[Column("IsScrap")]
public bool IsScrap { get; set; }
}
}
@@ -63,6 +63,7 @@
<Compile Include="ConfigModels\AlarmsConfigModel.cs" />
<Compile Include="ConfigModels\CmsConnectConfigModel.cs" />
<Compile Include="ConfigModels\ExtSoftwareModel.cs" />
<Compile Include="ConfigModels\InputOperatorConfigModel.cs" />
<Compile Include="ConfigModels\ThermoProdConfigModel.cs" />
<Compile Include="ConfigModels\ModBlockConfigModel.cs" />
<Compile Include="ConfigModels\RiskConfigModel.cs" />
@@ -106,6 +107,7 @@
<Compile Include="DTOModels\DTOAxesModel.cs" />
<Compile Include="DTOModels\DTOAxisNameModel.cs" />
<Compile Include="DTOModels\DTOClientConfigurationModel.cs" />
<Compile Include="DTOModels\DTOM156InputModel.cs" />
<Compile Include="DTOModels\ThModules\DTOModulesBlock.cs" />
<Compile Include="DTOModels\ThProd\DTOProdInfo.cs" />
<Compile Include="DTOModels\ThProd\DTOThermoPanelProd.cs" />
+193 -20
View File
@@ -3,6 +3,7 @@ using CMS_CORE_Library.Models;
using CMS_CORE_Library.S7Net;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.Linq;
using Thermo.Active.Database.Controllers;
@@ -53,6 +54,46 @@ namespace Thermo.Active.NC
/// </summary>
public static LiveData RecipeLiveData = new LiveData();
/// <summary>
/// Max number of param writable as single operation
/// </summary>
public int nMaxParamWrite
{
get
{
int answ = 5;
int.TryParse(ConfigurationManager.AppSettings["nMaxParamWrite"], out answ);
return answ;
}
}
/// <summary>
/// Delay between single param write operation
/// </summary>
public int delayParamWrite
{
get
{
int answ = 5;
int.TryParse(ConfigurationManager.AppSettings["delayParamWrite"], out answ);
return answ;
}
}
/// <summary>
/// Parametro lambda per EWMA smoothing
/// </summary>
public double ewmaLambda
{
get
{
int answ = 50;
int.TryParse(ConfigurationManager.AppSettings["ewmaPar100"], out answ);
return (double)answ / 100;
}
}
public NcAdapter() =>
// Choose NC
numericalControl = SetNumericalControl();
@@ -388,7 +429,7 @@ namespace Thermo.Active.NC
}
}
// se si in questo caso scrivo configurazione attuale...
WriteRecipeParams(updtRecipe);
WriteRecipeParams(updtRecipe, nMaxParamWrite, delayParamWrite);
// Ack !
libraryError = numericalControl.PLC_WAckConfRecipeRequest();
if (libraryError.IsError())
@@ -1229,6 +1270,45 @@ namespace Thermo.Active.NC
return numericalControl.PLC_RM154Data(ref data, ref MTCStatus);
}
public CmsError GetM156Data(out List<DTOM156InputModel> data)
{
data = new List<DTOM156InputModel>();
List<M156InputIsNeededModel> ncData = new List<M156InputIsNeededModel>();
CmsError cmsError = numericalControl.PLC_RM156Data(ref ncData);
if (cmsError.IsError())
return cmsError;
if (ncData.Count() > 0)
{
foreach (var m156Message in ncData)
{
var inp = InputsOperatorConfig.Where(x => m156Message.Id == x.Id).FirstOrDefault();
var buttons = inp.Buttons?.ToDictionary(x => x.Key, x => x.Key.ToString());
if (inp != null)
{
data.Add(new DTOM156InputModel()
{
Id = inp.Id,
isM156 = true,
Buttons = buttons,
Type = inp.Type,
Process = m156Message.Process,
Value = m156Message.Value
});
}
}
}
return NO_ERROR;
}
public CmsError WriteM156Data(int process, double responseValue)
{
return numericalControl.PLC_WM156Response(process, responseValue);
}
public CmsError WriteM154Ack(int processId)
{
return numericalControl.PLC_W154ManageAck(processId);
@@ -1384,7 +1464,16 @@ namespace Thermo.Active.NC
else
{
// confronto ultimo pezzo --> se diverso sono cambiati
dataChanged = (LastProdPanelData.NumDone != lastProdInfoData.NumDone);
bool changeSetpoint = true;
if (lastRecipe != null)
{
if (lastRecipe.ContainsKey("pyrometer_pyrometer_setpoint"))
{
changeSetpoint = LastProdPanelData.TempSetpoint != lastRecipe["pyrometer_pyrometer_setpoint"].SetpointPLC;
}
}
bool changeNumPz = LastProdPanelData.NumDone != lastProdInfoData.NumDone;
dataChanged = changeNumPz || changeSetpoint;
}
}
if (dataChanged)
@@ -1399,8 +1488,24 @@ namespace Thermo.Active.NC
{
currentProdPanel.LastCadenza = Math.Round((double)3600000 / lastProdInfoData.TimeCycleGross, 2);
}
// se il valore SALVATO è > 3 * valore rilevato --> uso SOLO ultimo
if (lastCycle > 3 * currentProdPanel.LastCadenza)
{
lastCycle = currentProdPanel.LastCadenza;
}
// altrimenti EWMA da parametro calcolato standard, default 50%
else
{
//lastCycle = 0.5 * lastCycle + 0.5 * lastDuration;
lastCycle = ewmaLambda * currentProdPanel.LastCadenza + (1 - ewmaLambda) * lastCycle;
}
// salvo anche nei live data della ricetta...
RecipeLiveData.TC_last = lastCycle;
// stima durata da pz fatti...
currentProdPanel.StimaDurata = Math.Round((currentProdPanel.NumTarget - currentProdPanel.NumDone) * currentProdPanel.LastTCiclo, 2);
//currentProdPanel.StimaDurata = Math.Round((currentProdPanel.NumTarget - currentProdPanel.NumDone) * currentProdPanel.LastTCiclo, 2);
// 2020.09.03 uso dati da ricetta corrente... stimata con EWMA, in SECONDI!
currentProdPanel.StimaDurata = Math.Round((currentProdPanel.NumTarget - currentProdPanel.NumDone) * lastCycle, 2) ;
// se stima negativa (+ pezzi di quanti richiesti...) --> ZERO!
currentProdPanel.StimaDurata = currentProdPanel.StimaDurata < 0 ? 0 : currentProdPanel.StimaDurata;
}
@@ -1455,6 +1560,7 @@ namespace Thermo.Active.NC
try
{
currentProdPanel.InizioProd = prodInfoFirst.FirstOrDefault().DtEvent;
lottoStart = currentProdPanel.InizioProd;
}
catch
{ }
@@ -1501,10 +1607,10 @@ namespace Thermo.Active.NC
// do comparison with old record and if changed --> persist on DB!
if (!prodInfoRawData.Equals(lastProdInfoData))
{
// save on DB! attenzione: num pezzi -1 perché salvo pezzo PRECEDENTE...
// save on DB! attenzione: RAW DATA perché salvo pezzo PRECEDENTE...
using (ProdInfoController prodInfoController = new ProdInfoController())
{
prodInfoController.Create(prodInfoRawData.NumTarget, prodInfoRawData.NumDone, prodInfoRawData.TimeWarm, prodInfoRawData.TimeVent, prodInfoRawData.TimeVacuum, prodInfoRawData.TimeCycleGross, prodInfoRawData.TimeCycleNet, prodInfoRawData.MaterialTempEndWarm, prodInfoRawData.MaterialTempEndVent, prodInfoRawData.MoldTemp, prodInfoRawData.VacuumReadVal, prodInfoRawData.MouldEnergyOUT, prodInfoRawData.MouldEnergyIN);
prodInfoController.Create(prodInfoRawData.NumTarget, prodInfoRawData.NumDone, prodInfoRawData.TimeWarm, prodInfoRawData.TimeVent, prodInfoRawData.TimeVacuum, prodInfoRawData.TimeCycleGross, prodInfoRawData.TimeCycleNet, prodInfoRawData.MaterialTempEndWarm, prodInfoRawData.MaterialTempEndVent, prodInfoRawData.MoldTemp, prodInfoRawData.VacuumReadVal, prodInfoRawData.MouldEnergyOUT, prodInfoRawData.MouldEnergyIN, false);
}
// update last info data
lastProdInfoData = prodInfoRawData;
@@ -1534,15 +1640,16 @@ namespace Thermo.Active.NC
lastProdEnd = DateTime.Now;
// calcolo ultimo ciclo...
var lastDuration = lastProdEnd.Subtract(lastProdStart).TotalSeconds;
// se il valore SALVATO è > 3 * valore rilevato (ma NON inferiore a 1/3...) --> uso SOLO ultimo
if ((lastCycle > 3 * lastDuration) && (lastCycle / 3 < lastDuration))
// se il valore SALVATO è > 3 * valore rilevato --> uso SOLO ultimo
if (lastCycle > 3 * lastDuration)
{
lastCycle = lastDuration;
}
// altrimenti EWMA 50%
// altrimenti EWMA da parametro calcolato standard, default 50%
else
{
lastCycle = 0.5 * lastCycle + 0.5 * lastDuration;
//lastCycle = 0.5 * lastCycle + 0.5 * lastDuration;
lastCycle = ewmaLambda * lastDuration + (1 - ewmaLambda) * lastCycle;
}
// salvo anche nei live data della ricetta...
RecipeLiveData.TC_last = lastCycle;
@@ -1588,26 +1695,45 @@ namespace Thermo.Active.NC
MoldTemp = x.MoldTemp,
VacuumReadVal = x.VacuumReadVal,
MouldEnergyOUT = x.MouldEnergyOUT,
MouldEnergyIN = x.MouldEnergyIN
MouldEnergyIN = x.MouldEnergyIN,
IsScrap = x.IsScrap
}).ToList();
}
return libraryError;
}
/// <summary>
/// Get historical prodinfo data from DB
/// </summary>
/// <param name="num"></param>
/// <param name="isScrap"></param>
/// <returns></returns>
public CmsError SetScrap(int num, bool isScrap)
{
CmsError libraryError = NO_ERROR;
using (ProdInfoController prodInfoController = new ProdInfoController())
{
prodInfoController.SetScrap(num, isScrap);
}
return libraryError;
}
/// <summary>
/// Update requested prod quantity
/// </summary>
/// <param name="numTarget"></param>
/// <param name="newWorkOrder"></param>
/// <param name="numTarget">Total qty requested</param>
/// <param name="newWorkOrder">Reset counter = new order</param>
/// <param name="preWarmCycle">Number of pre-warm cycle requested</param>
/// <returns></returns>
public CmsError UpdateProdInfoData(short numTarget, bool newWorkOrder)
public CmsError UpdateProdInfoData(short numTarget, bool newWorkOrder, short preWarmCycle)
{
CmsError libraryError = NO_ERROR;
using (ProdInfoController prodInfoController = new ProdInfoController())
{
// registro dati aggiornati sul PLC
libraryError = numericalControl.PLC_WProdInfo(numTarget, newWorkOrder);
libraryError = numericalControl.PLC_WProdInfo(numTarget, newWorkOrder, preWarmCycle);
if (libraryError.IsError())
return libraryError;
@@ -1761,9 +1887,11 @@ namespace Thermo.Active.NC
/// <summary>
/// Recipe Parameters write to PLC (only SetpointHMI)
/// </summary>
/// <param name="updtRecipe"></param>
/// <param name="updtRecipe">Oggetto parametri da aggiornare (from HMI)</param>
/// <param name="nMaxParamWrite">num max parametri da scrivere singolarmente</param>
/// <param name="delayParamWrite">delay in scriottura multi parametri singoli</param>
/// <returns></returns>
public CmsError WriteRecipeParametersToPLC(Dictionary<string, DTORecipeParam> updtRecipe)
public CmsError WriteRecipeParametersToPLC(Dictionary<string, DTORecipeParam> updtRecipe, int nMaxParamWrite, int delayParamWrite)
{
Dictionary<int, int> newParameters = new Dictionary<int, int>();
// solo x S7...
@@ -1775,7 +1903,7 @@ namespace Thermo.Active.NC
newParameters.Add(item.Value.Id, (int)(item.Value.SetpointHMI * item.Value.ScaleFactor));
}
// scrivo!
CmsError libraryError = numericalControl.PLC_WRecipeParameters(newParameters);
CmsError libraryError = numericalControl.PLC_WRecipeParameters(newParameters, nMaxParamWrite, delayParamWrite);
if (libraryError.IsError())
return libraryError;
}
@@ -2245,14 +2373,56 @@ namespace Thermo.Active.NC
/// Scrive tutti i parametri della ricetta indicati
/// </summary>
/// <param name="updtRecipe">Oggetto parametri da aggiornare (from HMI)</param>
/// <param name="nMaxParamWrite">num max parametri da scrivere singolarmente</param>
/// <param name="delayParamWrite">delay in scriottura multi parametri singoli</param>
/// <returns></returns>
public CmsError WriteRecipeParams(Dictionary<string, DTORecipeParam> updtRecipe)
public CmsError WriteRecipeParams(Dictionary<string, DTORecipeParam> updtRecipe, int nMaxParamWrite, int delayParamWrite)
{
CmsError libraryError = WriteRecipeParametersToPLC(updtRecipe);
CmsError libraryError = WriteRecipeParametersToPLC(updtRecipe, nMaxParamWrite, delayParamWrite);
return libraryError;
}
/// <summary>
/// Comparazione elenco parametri della ricetta
/// </summary>
/// <param name="dictSource"></param>
/// <param name="dictDest"></param>
/// <param name="isEqual"></param>
/// <returns></returns>
public CmsError paramsComparer(Dictionary<string, double> dictSource, Dictionary<string, double> dictDest, out bool isEqual)
{
CmsError libraryError = NO_ERROR;
// inizio dal count
isEqual = dictSource.Count==dictDest.Count;
// se uguale conteggio procedo...
if(isEqual)
{
foreach (var pair in dictSource)
{
double value;
if (dictDest.TryGetValue(pair.Key, out value))
{
// Require value be equal.
if (value != pair.Value)
{
isEqual = false;
break;
}
}
else
{
// Require key be present.
isEqual = false;
break;
}
}
}
// return ok!
return libraryError;
}
/// <summary>
/// Legge tutti i parametri della ricetta e calcolo la overview dei vari steps
/// </summary>
@@ -2422,7 +2592,10 @@ namespace Thermo.Active.NC
Visible = currModule.Visible,
Running = currModule.Running,
HasError = currModule.HasError,
Terminated = currModule.Terminated
Terminated = currModule.Terminated,
Category = item.Category,
SubCategory_1 = item.SubCategory_1,
SubCategory_2 = item.SubCategory_2
};
currModules.Add(item.Id, currVal);
}
+51 -38
View File
@@ -611,7 +611,9 @@ namespace Thermo.Active.NC
{
try
{
ReadLiveData();
RecipeLiveData = readLiveData();
// salva current
SaveRecipeCurrent();
}
catch (XmlException ex)
{
@@ -632,9 +634,9 @@ namespace Thermo.Active.NC
/// <summary>
/// Try to load live data from json persistence file
/// </summary>
public static bool ReadLiveData()
public static LiveData readLiveData()
{
bool answ = false;
LiveData answ = null;
if (File.Exists(LIVE_RECIPE_PATH))
{
// load all text data
@@ -642,11 +644,10 @@ namespace Thermo.Active.NC
try
{
// deserialize to object
RecipeLiveData = JsonConvert.DeserializeObject<LiveData>(rawData);
answ = JsonConvert.DeserializeObject<LiveData>(rawData);
}
catch
{ }
answ = true;
}
else
{
@@ -655,18 +656,15 @@ namespace Thermo.Active.NC
try
{
// deserialize to object
RecipeLiveData = JsonConvert.DeserializeObject<LiveData>(rawData);
answ = JsonConvert.DeserializeObject<LiveData>(rawData);
// from template --> reset (if present) overview data...
foreach (var item in RecipeLiveData.RecipeOverview)
{
RecipeLiveData.RecipeOverview[item.Key] = RecipeCatStatus.Unchanged;
answ.RecipeOverview[item.Key] = RecipeCatStatus.Unchanged;
}
}
catch
{ }
// salva current
SaveRecipeCurrent();
answ = true;
}
// rendo se fatto
return answ;
@@ -674,9 +672,9 @@ namespace Thermo.Active.NC
/// <summary>
/// Try to load selected recipe to live data (memory and json persistence file)
/// </summary>
public static bool LoadRecipe(string filePath)
public static LiveData LoadRecipe(string filePath)
{
bool answ = false;
LiveData answ = null;
// check file extension: accetta json / rcp / tpl
if (!(filePath.EndsWith(".json") || filePath.EndsWith(".rcp") || filePath.EndsWith(".tpl")))
{
@@ -689,27 +687,27 @@ namespace Thermo.Active.NC
if (!Path.IsPathRooted(filePath))
{
// controllo se ha path della recipe directory
if (!filePath.Contains(RECIPE_DIRECTORY) && filePath != RECIPE_TEMPLATE_PATH)
if (!filePath.Contains(NcConfig.SharedPath) && filePath != RECIPE_TEMPLATE_PATH)
{
// aggiungo base path!
filePath = RECIPE_DIRECTORY + filePath;
filePath = NcConfig.SharedPath + filePath;
}
}
if (File.Exists(filePath))
{
answ = true;
// load all text data
var rawData = File.ReadAllText(filePath);
try
{
// deserialize to object
RecipeLiveData = JsonConvert.DeserializeObject<LiveData>(rawData);
answ = JsonConvert.DeserializeObject<LiveData>(rawData);
// fix directory se mancasse
answ.RecipeDir = $"{Path.GetDirectoryName(filePath)}\\";
// fix Modifica dati
answ.hasChanged = false;
}
catch
{ }
// update current live data!
SaveRecipeCurrent();
}
// rendo se fatto
return answ;
@@ -731,6 +729,10 @@ namespace Thermo.Active.NC
{
// deserialize to object
RecipeLiveData = JsonConvert.DeserializeObject<LiveData>(rawData);
// fix directory default
RecipeLiveData.RecipeDir = NcConfig.SharedPath;
// fix Modifica dati
RecipeLiveData.hasChanged = false;
// from template --> reset (if present) overview data...
if (RecipeLiveData.RecipeOverview != null)
{
@@ -758,16 +760,18 @@ namespace Thermo.Active.NC
bool answ = false;
try
{
answ = true;
// indico che ora è OK x salvataggio...
RecipeLiveData.hasChanged = false;
// serialize
string rawData = JsonConvert.SerializeObject(RecipeLiveData, Newtonsoft.Json.Formatting.Indented);
// save live!
var dir = Path.GetDirectoryName(LIVE_RECIPE_PATH);
var dir = $"{Path.GetDirectoryName(LIVE_RECIPE_PATH)}\\";
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
File.WriteAllText(LIVE_RECIPE_PATH, rawData);
answ = true;
}
catch
{ }
@@ -786,31 +790,38 @@ namespace Thermo.Active.NC
try
{
// save live!
var dir = Path.GetDirectoryName(RECIPE_DIRECTORY);
var dir = $"{Path.GetDirectoryName(NcConfig.SharedPath)}\\";
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
// se non ho name valido --> FIX come svg...
if (!filePath.EndsWith(".svg"))
{
filePath = RecipeLiveData.RecipeName.Replace(".rcp", ".svg");
}
// Delete previous image
if (File.Exists(filePath))
{
File.Delete(filePath);
}
if (!Path.IsPathRooted(filePath))
{
// aggiungo base path!
filePath = RECIPE_DIRECTORY + filePath;
// aggiungo base path! se ho path della ricetta corrente uso quella...
string currPath = RecipeLiveData.RecipeDir;
if (!string.IsNullOrEmpty(currPath))
{
currPath = NcConfig.SharedPath;
}
filePath = $"{currPath}{filePath}";
}
// Save NEW image
File.WriteAllBytes(filePath, fileData);
imageUploaded = true;
}
catch
{ }
return imageUploaded;
}
/// <summary>
@@ -820,6 +831,7 @@ namespace Thermo.Active.NC
{
// duplicate data...
LiveData data2save = RecipeLiveData;
data2save.RecipeDir = NcConfig.SharedPath;
// template --> reset overview data...
data2save.RecipeOverview = new Dictionary<RecipeSection, RecipeCatStatus>();
return SaveRecipe(RECIPE_TEMPLATE_PATH, data2save);
@@ -839,24 +851,25 @@ namespace Thermo.Active.NC
// default: ricetta!
filePath += ".rcp";
}
string fileName = Path.GetFileName(filePath);
// fix name!
currRecipe.RecipeName = fileName;
// serialize
string rawData = JsonConvert.SerializeObject(currRecipe, Newtonsoft.Json.Formatting.Indented);
// save live!
File.WriteAllText(LIVE_RECIPE_PATH, rawData);
// verifica path
if (!Path.IsPathRooted(filePath))
{
// controllo se ha path della recipe directory
if (!filePath.Contains(RECIPE_DIRECTORY) && filePath != RECIPE_TEMPLATE_PATH)
if (!filePath.Contains(NcConfig.SharedPath) && filePath != RECIPE_TEMPLATE_PATH)
{
// aggiungo base path!
filePath = RECIPE_DIRECTORY + filePath;
filePath = NcConfig.SharedPath + filePath;
}
}
// fix name, path, modifica!
currRecipe.RecipeName = Path.GetFileName(filePath);
currRecipe.RecipeDir = $"{Path.GetDirectoryName(filePath)}\\";
currRecipe.hasChanged = false;
// serialize
string rawData = JsonConvert.SerializeObject(currRecipe, Newtonsoft.Json.Formatting.Indented);
// save live!
File.WriteAllText(LIVE_RECIPE_PATH, rawData);
// save!
File.WriteAllText(filePath, rawData);
}
+1
View File
@@ -37,6 +37,7 @@
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
+3
View File
@@ -14,6 +14,9 @@
<add key="enableDirectoryBrowsing" value="true" />
<add key="ClientSettingsProvider.ServiceUri" value="" />
<add key="ServerServiceName" value="MariaDB" />
<add key="nMaxParamWrite" value="5" />
<add key="delayParamWrite" value="10" />
<add key="ewmaPar100" value="40" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.6.2" />
@@ -183,6 +183,19 @@ namespace Thermo.Active.Controllers.SignalR
}
#endif
[SignalRAuthorize(FunctionAccess = GENERAL, Action = ACTIONS.WRITE)]
public void WriteM156Response(int process, double responseVal)
{
using (NcAdapter ncAdapter = new NcAdapter())
{
ncAdapter.Connect();
CmsError cmsError = ncAdapter.WriteM156Data(process, responseVal);
if (cmsError.IsError())
throw new HubException(cmsError.localizationKey);
}
}
[SignalRAuthorize(FunctionAccess = GENERAL, Action = ACTIONS.WRITE)]
public void WriteScadaValue(string memIndex, SCADA_MEM_TYPE memType, object value)
{
@@ -55,10 +55,10 @@ namespace Thermo.Active.Controllers.WebApi
Dictionary<string, string> alarmsNames = GetPlcAlarmsTranslations(language);
Dictionary<string, string> headsNames = GetLocalizedHeadsNames(language);
// scada
Dictionary<string, string> scadaTranslations = GetScadaTranslations(language);
Dictionary<string, string> m156Translations = GetM156Translations(language);
// THermo (modules and recipe enums) translations
// Thermo (modules and recipe enums) translations
Dictionary<string, string> thermoTranslations = GetThermoTranslations(language);
@@ -72,7 +72,9 @@ namespace Thermo.Active.Controllers.WebApi
translations = translations.Concat(headsNames).ToDictionary(x => x.Key, x => x.Value);
// Scada
translations = translations.Concat(scadaTranslations).ToDictionary(x => x.Key, x => x.Value);
// Scada
// M156
translations = translations.Concat(m156Translations).ToDictionary(x => x.Key, x => x.Value);
// Thermo
translations = translations.Concat(thermoTranslations).ToDictionary(x => x.Key, x => x.Value);
if (translations == null)
@@ -210,5 +212,31 @@ namespace Thermo.Active.Controllers.WebApi
return translatedNames;
}
public static Dictionary<string, string> GetM156Translations(string language)
{
Dictionary<string, string> translatedNames = new Dictionary<string, string>();
foreach (var input in InputsOperatorConfig)
{
translatedNames.Add(
"m156_title_" + input.Id,
GetValueFromLocalizationList(input.Messages, language, "Title_" + input.Id)
);
if (input.Buttons != null && input.Buttons.Count() > 0)
foreach (var button in input.Buttons)
{
// Add translated button text to the list
// Buttons have a Dictionary<string, string> with the translations
translatedNames.Add(
"m156_" + input.Id + "_button_" + button.Key,
GetValueFromLocalizationList(button.Value, language, "Button_" + button.Key)
);
}
}
return translatedNames;
}
}
}
@@ -45,6 +45,7 @@ namespace Thermo.Active.Controllers.WebApi
// ritorno solo fatto!
return Ok();
}
#if true
/// <summary>
/// Request mode AUTO
/// </summary>
@@ -71,7 +72,8 @@ namespace Thermo.Active.Controllers.WebApi
// ritorno solo fatto!
return Ok();
}
}
#endif
/// <summary>
/// Request mode SETUP
/// </summary>
@@ -100,9 +102,42 @@ namespace Thermo.Active.Controllers.WebApi
return Ok();
}
/// <summary>
/// Set item as scrap
/// </summary>
/// <param name="num">item NUM</param>
/// <param name="isScrap">scrap flag (true/false)</param>
/// <returns></returns>
[Route("setScrap"), HttpPut]
[WebApiAuthorize(FunctionAccess = FUNCTIONALITY_NAMES.RECIPE_MANAGER, Action = ACTIONS.READ)]
public IHttpActionResult SetScrap(int num, bool isScrap)
{
// Try connection
CmsError libraryError = ncAdapter.Connect();
if (libraryError.IsError())
{
ThermoActiveLogger.LogError($"NC Not connected! | SetScrap | {libraryError.exception}");
return BadRequest(libraryError.localizationKey);
}
// scrivo sul DB che il pezzo è SCRAPPED
libraryError = ncAdapter.SetScrap(num, isScrap);
if (libraryError.IsError())
{
ThermoActiveLogger.LogError($"SetScrap error | {libraryError.exception}");
return BadRequest(libraryError.localizationKey);
}
// ritorno solo fatto!
return Ok();
}
/// <summary>
/// Request start production
/// </summary>
/// <param name="requestQty">item NUM</param>
/// <param name="newWorkOrder">scrap flag (true/false)</param>
/// <returns></returns>
[Route("start"), HttpPut]
[WebApiAuthorize(FunctionAccess = FUNCTIONALITY_NAMES.RECIPE_MANAGER, Action = ACTIONS.READ)]
@@ -116,19 +151,73 @@ namespace Thermo.Active.Controllers.WebApi
return BadRequest(libraryError.localizationKey);
}
// scrivo sul PLC il comando strobe richiesta AUTO!
libraryError = ncAdapter.UpdateProdInfoData((short)requestQty, newWorkOrder);
// legacy method
short numCicliRisc = 0;
// scrivo sul PLC pezzi richiesti, cicli riscaldo + comando strobe reset se encessario!
libraryError = ncAdapter.UpdateProdInfoData((short)requestQty, newWorkOrder, numCicliRisc);
if (libraryError.IsError())
{
ThermoActiveLogger.LogError($"StartProd error | {libraryError.exception}");
return BadRequest(libraryError.localizationKey);
}
// se new workorder --> registro nuova data lorro!
// se new workorder --> registro nuova data x start lotto!
if (newWorkOrder)
{
ncAdapter.lottoStart = DateTime.Now;
}
// scrivo sul PLC il comando strobe richiesta AUTO!
libraryError = ncAdapter.StrobeMode(Mode.AUTO);
if (libraryError.IsError())
{
ThermoActiveLogger.LogError($"RequestAuto error | {libraryError.exception}");
return BadRequest(libraryError.localizationKey);
}
// ritorno solo fatto!
return Ok();
}
/// <summary>
/// Request start production
/// </summary>
/// <param name="requestQty">item NUM</param>
/// <param name="newWorkOrder">scrap flag (true/false)</param>
/// <param name="numCicliRisc">warmup cycle requested (0=none)</param>
/// <returns></returns>
[Route("startFull"), HttpPut]
[WebApiAuthorize(FunctionAccess = FUNCTIONALITY_NAMES.RECIPE_MANAGER, Action = ACTIONS.READ)]
public IHttpActionResult StartProdFull(int requestQty, bool newWorkOrder, int numCicliRisc)
{
// Try connection
CmsError libraryError = ncAdapter.Connect();
if (libraryError.IsError())
{
ThermoActiveLogger.LogError($"NC Not connected! | StartProd | {libraryError.exception}");
return BadRequest(libraryError.localizationKey);
}
// scrivo sul PLC pezzi richiesti, cicli riscaldo + comando strobe reset se encessario!
libraryError = ncAdapter.UpdateProdInfoData((short)requestQty, newWorkOrder, (short)numCicliRisc);
if (libraryError.IsError())
{
ThermoActiveLogger.LogError($"StartProd error | {libraryError.exception}");
return BadRequest(libraryError.localizationKey);
}
// se new workorder --> registro nuova data x start lotto!
if (newWorkOrder)
{
ncAdapter.lottoStart = DateTime.Now;
}
// scrivo sul PLC il comando strobe richiesta AUTO!
libraryError = ncAdapter.StrobeMode(Mode.AUTO);
if (libraryError.IsError())
{
ThermoActiveLogger.LogError($"RequestAuto error | {libraryError.exception}");
return BadRequest(libraryError.localizationKey);
}
// ritorno solo fatto!
return Ok();
}
@@ -1,6 +1,7 @@
using CMS_CORE_Library.Models;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
@@ -69,6 +70,16 @@ namespace Thermo.Active.Controllers.WebApi
return Ok(currRecipe);
}
[Route("recipeNotes"), HttpGet]
public IHttpActionResult GetRecipeNotes()
{
return Ok(NcAdapter.RecipeLiveData.recipeNotes);
}
[Route("recipeChanged"), HttpGet]
public IHttpActionResult GetChanged()
{
return Ok(NcAdapter.RecipeLiveData.hasChanged);
}
[Route("update"), HttpPut]
[WebApiAuthorize(FunctionAccess = FUNCTIONALITY_NAMES.RECIPE_MANAGER, Action = ACTIONS.READ)]
@@ -76,7 +87,7 @@ namespace Thermo.Active.Controllers.WebApi
{
if (parametersList != null)
{
if (NcFileAdapter.RecipeLiveData != null)
if (NcAdapter.RecipeLiveData != null)
{
// Try connection
CmsError libraryError = ncAdapter.Connect();
@@ -118,8 +129,10 @@ namespace Thermo.Active.Controllers.WebApi
if (updtRecipe.Count > 0)
{
// scrivo sul PLC
ncAdapter.WriteRecipeParams(updtRecipe);
// salvo che la ricetta è cambiata
NcAdapter.RecipeLiveData.hasChanged = true;
// scrivo sul PLC con i parametri specificati x ritardo/raggruppamento
ncAdapter.WriteRecipeParams(updtRecipe, ncAdapter.nMaxParamWrite, ncAdapter.delayParamWrite);
}
// ritorno solo fatto!
@@ -147,7 +160,7 @@ namespace Thermo.Active.Controllers.WebApi
[WebApiAuthorize(FunctionAccess = FUNCTIONALITY_NAMES.RECIPE_MANAGER, Action = ACTIONS.READ)]
public IHttpActionResult ConfirmEdit(RecipeSection section)
{
if (NcFileAdapter.RecipeLiveData != null)
if (NcAdapter.RecipeLiveData != null)
{
// Try connection
CmsError libraryError = ncAdapter.Connect();
@@ -210,7 +223,7 @@ namespace Thermo.Active.Controllers.WebApi
[WebApiAuthorize(FunctionAccess = FUNCTIONALITY_NAMES.RECIPE_MANAGER, Action = ACTIONS.READ)]
public IHttpActionResult CancelEdit()
{
if (NcFileAdapter.RecipeLiveData != null)
if (NcAdapter.RecipeLiveData != null)
{
// Try connection
CmsError libraryError = ncAdapter.Connect();
@@ -230,6 +243,7 @@ namespace Thermo.Active.Controllers.WebApi
// recupero i dati LIVE dei parametri HMI della ricetta...
libraryError = ncAdapter.ReadFullRecipe(out Dictionary<string, DTORecipeParam> currRecipe);
if (libraryError.IsError())
{
ThermoActiveLogger.LogError($"ConfirmEdit error | {libraryError.exception}");
@@ -266,13 +280,18 @@ namespace Thermo.Active.Controllers.WebApi
{
// chiamo metodo di lettura...
bool fatto = NcFileAdapter.LoadRecipe(newName);
if (!fatto)
var dataRead = NcFileAdapter.LoadRecipe(newName);
if (dataRead == null)
{
ThermoActiveLogger.LogError($"LoadRecipe error");
return NotFound();
}
// salvo in memoria ricetta live
NcAdapter.RecipeLiveData = dataRead;
// update current live data!
NcFileAdapter.SaveRecipeCurrent();
CmsError libraryError = WriteCurrentRecipeToPlc();
if (libraryError.IsError())
{
@@ -329,7 +348,7 @@ namespace Thermo.Active.Controllers.WebApi
using (UsersController usersController = new UsersController())
{
var userData = usersController.GetUserInfo(Convert.ToInt32(userId.Value));
NcFileAdapter.RecipeLiveData.UserSave = userData.Id.ToString();
NcAdapter.RecipeLiveData.UserSave = userData.Id.ToString();
}
// recupero i dati LIVE dei parametri HMI della ricetta...
@@ -367,7 +386,7 @@ namespace Thermo.Active.Controllers.WebApi
using (UsersController usersController = new UsersController())
{
var userData = usersController.GetUserInfo(Convert.ToInt32(userId.Value));
NcFileAdapter.RecipeLiveData.UserSave = userData.Id.ToString();
NcAdapter.RecipeLiveData.UserSave = userData.Id.ToString();
}
// recupero i dati LIVE dei parametri HMI della ricetta...
@@ -385,9 +404,9 @@ namespace Thermo.Active.Controllers.WebApi
}
// ora salvo ANCHE i dati live...
NcFileAdapter.RecipeLiveData.RecipeParameters = currParams;
NcAdapter.RecipeLiveData.RecipeParameters = currParams;
// e salvo su disco
NcFileAdapter.SaveRecipe(newName, NcFileAdapter.RecipeLiveData);
NcFileAdapter.SaveRecipe(newName, NcAdapter.RecipeLiveData);
// ritorno solo fatto!
return Ok();
@@ -425,7 +444,7 @@ namespace Thermo.Active.Controllers.WebApi
}
// ora salvo nei dati live...
NcFileAdapter.RecipeLiveData.RecipeParameters = currParams;
NcAdapter.RecipeLiveData.RecipeParameters = currParams;
// carico i dati dei riscaldi...
var currChSet = new Dictionary<int, int>();
@@ -433,7 +452,7 @@ namespace Thermo.Active.Controllers.WebApi
{
currChSet.Add(item.Key, item.Value.SetpointHMI);
}
NcFileAdapter.RecipeLiveData.ChannelSetpoints = currChSet;
NcAdapter.RecipeLiveData.ChannelSetpoints = currChSet;
// e salvo su disco
@@ -478,10 +497,10 @@ namespace Thermo.Active.Controllers.WebApi
// salvo note...
if (!string.IsNullOrEmpty(recipeNotes))
{
NcFileAdapter.RecipeLiveData.recipeNotes = recipeNotes.Trim();
NcAdapter.RecipeLiveData.recipeNotes = recipeNotes.Trim();
}
// e salvo su disco
NcFileAdapter.SaveRecipe(NcFileAdapter.RecipeLiveData.RecipeName, NcFileAdapter.RecipeLiveData);
NcFileAdapter.SaveRecipe(NcAdapter.RecipeLiveData.RecipeName, NcAdapter.RecipeLiveData);
return Ok();
}
@@ -499,13 +518,13 @@ namespace Thermo.Active.Controllers.WebApi
using (UsersController usersController = new UsersController())
{
var userData = usersController.GetUserInfo(Convert.ToInt32(userId.Value));
NcFileAdapter.RecipeLiveData.UserSave = userData.Id.ToString();
NcAdapter.RecipeLiveData.UserSave = userData.Id.ToString();
}
// salvo note...
if (!string.IsNullOrEmpty(recipeNotes))
{
NcFileAdapter.RecipeLiveData.recipeNotes = recipeNotes.Trim();
NcAdapter.RecipeLiveData.recipeNotes = recipeNotes.Trim();
}
bool imageUploaded = false;
@@ -544,15 +563,17 @@ namespace Thermo.Active.Controllers.WebApi
currParams.Add(item.Key, item.Value.SetpointPLC);
}
// salvo parametri
NcFileAdapter.RecipeLiveData.RecipeParameters = currParams;
NcAdapter.RecipeLiveData.RecipeParameters = currParams;
// ora salvo il dato del TC stimato se presente
if (estimTimeSec > 0)
{
NcFileAdapter.RecipeLiveData.TC_last = estimTimeSec;
NcAdapter.RecipeLiveData.TC_last = estimTimeSec;
}
// indico che non è + modificata...
NcAdapter.RecipeLiveData.hasChanged = false;
// e salvo su disco
NcFileAdapter.SaveRecipe(newName, NcFileAdapter.RecipeLiveData);
NcFileAdapter.SaveRecipe(newName, NcAdapter.RecipeLiveData);
}
return Ok();
}
@@ -566,7 +587,13 @@ namespace Thermo.Active.Controllers.WebApi
try
{
// ora salvo ANCHE i dati live...
NcFileAdapter.RecipeLiveData.RecipeParameters = currParams;
NcAdapter.RecipeLiveData.RecipeParameters = currParams;
// verifico SE siano cambiati rispetto a versione originale...
var originalRecipe = NcFileAdapter.LoadRecipe($"{NcAdapter.RecipeLiveData.RecipeDir}{NcAdapter.RecipeLiveData.RecipeName}");
// comparazione parametri...
bool isEqual = false;
ncAdapter.paramsComparer(originalRecipe.RecipeParameters, currParams, out isEqual);
NcAdapter.RecipeLiveData.hasChanged = !isEqual;
// e salvo su disco
NcFileAdapter.SaveRecipeCurrent();
}
@@ -603,7 +630,7 @@ namespace Thermo.Active.Controllers.WebApi
// save parameters to PLC!!!
Dictionary<string, DTORecipeParam> updtRecipe = new Dictionary<string, DTORecipeParam>();
foreach (var item in NcFileAdapter.RecipeLiveData.RecipeParameters)
foreach (var item in NcAdapter.RecipeLiveData.RecipeParameters)
{
if (prevRecipe.ContainsKey(item.Key))
{
@@ -621,7 +648,7 @@ namespace Thermo.Active.Controllers.WebApi
}
// write to PLC
checkError = ncAdapter.WriteRecipeParams(updtRecipe);
checkError = ncAdapter.WriteRecipeParams(updtRecipe, ncAdapter.nMaxParamWrite, ncAdapter.delayParamWrite);
if (checkError.IsError())
{
ThermoActiveLogger.LogError($"WriteCurrentRecipeToPlc | WriteRecipeParams error | {checkError.exception}");
@@ -631,7 +658,7 @@ namespace Thermo.Active.Controllers.WebApi
// process ch load setup...
Dictionary<int, int> newRisk = new Dictionary<int, int>();
foreach (var item in NcFileAdapter.RecipeLiveData.ChannelSetpoints)
foreach (var item in NcAdapter.RecipeLiveData.ChannelSetpoints)
{
newRisk.Add(item.Key, item.Value);
}
@@ -238,7 +238,7 @@ namespace Thermo.Active.Controllers.WebApi
try
{
// ora salvo ANCHE i dati live...
NcFileAdapter.RecipeLiveData.ChannelSetpoints = chSetpoints;
NcAdapter.RecipeLiveData.ChannelSetpoints = chSetpoints;
// e salvo su disco
NcFileAdapter.SaveRecipeCurrent();
}
+4 -6
View File
@@ -78,12 +78,6 @@ namespace Thermo.Active.Listeners
SignalRListener.SendPartProgramQueue(a);
SignalRDatabaseHandler.UpdateQueue(a);
}));
#if false
infos.Add(MessageServices.Current.Subscribe(SEND_M155_DATA, (a, b) =>
{
SignalRListener.SendM155Data(a);
}));
#endif
infos.Add(MessageServices.Current.Subscribe(SEND_SCADA_DATA, (a, b) =>
{
SignalRListener.SendScadaData(a);
@@ -92,6 +86,10 @@ namespace Thermo.Active.Listeners
{
SignalRListener.SetGatewayRebootStatus(a);
}));
infos.Add(MessageServices.Current.Subscribe(SEND_M156_DATA, (a, b) =>
{
SignalRListener.SendM156Data(a);
}));
// add specific modules for THERMO
infos.Add(MessageServices.Current.Subscribe(SEND_THERMO_RECIPE_FULL, (a, b) =>
@@ -239,6 +239,17 @@ namespace Thermo.Active.Listeners.SignalR
}
}
#endif
public static void SendM156Data(object data)
{
List<DTOM156InputModel> dtoM156Data = data as List<DTOM156InputModel>;
if (!LastM156Data.SequenceEqual(dtoM156Data))
{
LastM156Data = dtoM156Data;
var context = GlobalHost.ConnectionManager.GetHubContext<NcHub>();
context.Clients.Group("ncData").m156Data(dtoM156Data);
}
}
public static void SendScadaData(object scada)
{
@@ -455,6 +466,8 @@ namespace Thermo.Active.Listeners.SignalR
}
}
public static void SetGatewayRebootStatus(object status)
{
string msg = status.ToString();
@@ -514,10 +527,9 @@ namespace Thermo.Active.Listeners.SignalR
group.magazineIsActive(LastNcMagazineIsActive);
// Send PP Queue
group.partProgramQueue(LastPartProgramQueue);
#if false
// Send m155 data
group.m155Data(LastM155Data);
#endif
// Send m156
group.m156Data(LastM156Data);
// Send Scada
group.scadaData(LastScadaData);
@@ -30,6 +30,7 @@ namespace Thermo.Active.Listeners
#if false
public static List<DTOM155InputModel> LastM155Data = new List<DTOM155InputModel>();
#endif
public static List<DTOM156InputModel> LastM156Data = new List<DTOM156InputModel>();
public static List<DTOScadaModel> LastScadaData = new List<DTOScadaModel>();
// FIXME TODO inserire oggetti corretti per THERMO
+1 -1
View File
@@ -30,4 +30,4 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("0.12.65")]
[assembly: AssemblyVersion("0.14.80")]
@@ -2378,7 +2378,7 @@
line-height: 4px;
.title {
width: 110px;
min-width: 110px;
text-align: right;
color: @color-darkish-blue;
}
@@ -256,11 +256,11 @@
align-items: center;
display: flex;
border-radius: 7px;
&.fa-check-circle {
color: #90BF3D;
}
&.fa-check-circle.undone-step {
color: #1791FF;
}
@@ -474,6 +474,8 @@ article {
padding-bottom: 10px;
padding-top: 5px;
border: 2px solid #979797;
box-sizing: border-box;
align-items: center;
}
.submit {
@@ -385,6 +385,8 @@ article .box .body {
padding-bottom: 10px;
padding-top: 5px;
border: 2px solid #979797;
box-sizing: border-box;
align-items: center;
}
.box .submit {
margin: auto;
@@ -2521,7 +2523,7 @@ article .box .body {
.modal.modal-add-element-queue .modal-load-program-body .selected-item .selected-item-header .subtitle .title,
.modal.modal-load-program .modal-add-element-queue-body .selected-item .selected-item-header .subtitle .title,
.modal.modal-add-element-queue .modal-add-element-queue-body .selected-item .selected-item-header .subtitle .title {
width: 110px;
min-width: 110px;
text-align: right;
color: #002680;
}
@@ -7,301 +7,301 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="disegno-quote-velocita-stampo.svg"
id="svg8"
version="1.1"
viewBox="0 0 297 210"
width="297"
height="210"
width="297">
viewBox="0 0 297 210"
version="1.1"
id="svg8"
sodipodi:docname="disegno-quote-velocita-stampo.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
<sodipodi:namedview
inkscape:object-nodes="false"
inkscape:current-layer="layer1"
inkscape:window-maximized="1"
inkscape:window-y="-9"
inkscape:window-x="-9"
inkscape:cy="51.482576"
inkscape:cx="187.49592"
inkscape:zoom="2.9247028"
showgrid="false"
id="namedview907"
inkscape:window-height="1001"
inkscape:window-width="1920"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
pagecolor="#ffffff" />
inkscape:document-rotation="0"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1056"
id="namedview907"
showgrid="false"
inkscape:zoom="2.9247028"
inkscape:cx="187.49592"
inkscape:cy="51.482576"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
inkscape:object-nodes="false" />
<defs
id="defs2">
<inkscape:perspective
id="perspective32764"
inkscape:persp3d-origin="148.5 : 70 : 1"
inkscape:vp_z="297 : 105 : 1"
inkscape:vp_y="0 : 1000 : 0"
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 105 : 1"
sodipodi:type="inkscape:persp3d" />
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="297 : 105 : 1"
inkscape:persp3d-origin="148.5 : 70 : 1"
id="perspective32764" />
<marker
inkscape:isstock="true"
inkscape:stockid="ExperimentalArrow"
orient="auto-start-reverse"
refY="3.0"
refX="5.0"
id="marker1181"
refX="5.0"
refY="3.0"
orient="auto-start-reverse"
inkscape:stockid="ExperimentalArrow">
inkscape:isstock="true">
<path
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1"
id="path1179"
d="m 10,3 -10,3 0,-6 z"
id="path1179" />
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lend"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#bbbcbc;stroke-width:1pt;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path912" />
</marker>
<marker
orient="auto"
refY="0.0"
refX="0.0"
id="marker1176"
style="overflow:visible">
<path
id="path1055"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
style="fill-rule:evenodd;stroke:#bbbcbc;stroke-width:1pt;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
transform="scale(0.8)" />
</marker>
<marker
style="overflow:visible"
id="TriangleOutL"
refX="0.0"
refY="0.0"
orient="auto">
<path
transform="scale(0.8)"
style="fill-rule:evenodd;stroke:#bbbcbc;stroke-width:1pt;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
id="path1162" />
</marker>
<marker
orient="auto-start-reverse"
refY="3.0"
refX="5.0"
id="marker4178">
<path
id="path4176"
d="m 10,3 -10,3 0,-6 z"
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1" />
</marker>
<marker
orient="auto-start-reverse"
refY="3.0"
refX="5.0"
id="marker4066">
<path
id="path4064"
d="m 10,3 -10,3 0,-6 z"
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1" />
</marker>
<marker
orient="auto-start-reverse"
refY="3.0"
refX="5.0"
id="marker3448">
<path
id="path3446"
d="m 10,3 -10,3 0,-6 z"
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1" />
</marker>
<marker
id="marker3312"
refX="5.0"
refY="3.0"
orient="auto-start-reverse">
<path
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1"
d="m 10,3 -10,3 0,-6 z"
id="path3310" />
</marker>
<marker
style="overflow:visible"
id="StopL"
refX="0.0"
refY="0.0"
orient="auto">
<path
transform="scale(0.8)"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#bbbcbc;stroke-width:1pt;stroke-opacity:1"
d="M 0.0,5.65 L 0.0,-5.65"
id="path1189" />
</marker>
<marker
orient="auto-start-reverse"
refY="3.0"
refX="5.0"
id="marker1984">
<path
id="path1982"
d="m 10,3 -10,3 0,-6 z"
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1" />
</marker>
<marker
orient="auto-start-reverse"
refY="3.0"
refX="5.0"
id="marker1920">
<path
id="path1918"
d="m 10,3 -10,3 0,-6 z"
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1" />
</marker>
<marker
style="overflow:visible"
id="marker1502"
refX="0.0"
refY="0.0"
orient="auto">
<path
transform="scale(0.6) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
id="path1500" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Sstart"
refX="0.0"
refY="0.0"
orient="auto">
<path
transform="scale(0.3) translate(-2.3,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#bbbcbc;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
id="path1050" />
</marker>
<marker
style="overflow:visible"
id="marker1406"
refX="0.0"
refY="0.0"
orient="auto">
<path
transform="scale(0.4) translate(10,0)"
style="fill-rule:evenodd;stroke:#bbbcbc;stroke-width:1pt;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path1404" />
</marker>
<marker
style="overflow:visible;"
id="Arrow2Mend"
refX="0.0"
refY="0.0"
orient="auto">
inkscape:isstock="true">
<path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#bbbcbc;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
id="path1047" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Mstart"
refX="0.0"
refY="0.0"
orient="auto">
<path
transform="scale(0.6) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#bbbcbc;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
id="path1044" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Mstart"
refX="0.0"
refY="0.0"
orient="auto">
<path
transform="scale(0.4) translate(10,0)"
style="fill-rule:evenodd;stroke:#bbbcbc;stroke-width:1pt;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
id="path912"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path1026" />
style="fill-rule:evenodd;stroke:#bbbcbc;stroke-width:1pt;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
id="ExperimentalArrow"
style="overflow:visible"
id="marker1176"
refX="0.0"
refY="0.0"
orient="auto">
<path
transform="scale(0.8)"
style="fill-rule:evenodd;stroke:#bbbcbc;stroke-width:1pt;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
id="path1055" />
</marker>
<marker
orient="auto"
refY="0.0"
refX="0.0"
id="TriangleOutL"
style="overflow:visible">
<path
id="path1162"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
style="fill-rule:evenodd;stroke:#bbbcbc;stroke-width:1pt;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
transform="scale(0.8)" />
</marker>
<marker
id="marker4178"
refX="5.0"
refY="3.0"
orient="auto-start-reverse">
<path
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1"
d="m 10,3 -10,3 0,-6 z"
id="path1273" />
id="path4176" />
</marker>
<marker
id="marker4066"
refX="5.0"
refY="3.0"
orient="auto-start-reverse">
<path
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1"
d="m 10,3 -10,3 0,-6 z"
id="path4064" />
</marker>
<marker
id="marker3448"
refX="5.0"
refY="3.0"
orient="auto-start-reverse">
<path
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1"
d="m 10,3 -10,3 0,-6 z"
id="path3446" />
</marker>
<marker
orient="auto-start-reverse"
refY="3"
refX="5"
id="ExperimentalArrow-5">
refY="3.0"
refX="5.0"
id="marker3312">
<path
id="path1273-2"
d="M 10,3 0,6 V 0 Z"
id="path3310"
d="m 10,3 -10,3 0,-6 z"
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1" />
</marker>
<marker
orient="auto"
refY="0.0"
refX="0.0"
id="StopL"
style="overflow:visible">
<path
id="path1189"
d="M 0.0,5.65 L 0.0,-5.65"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#bbbcbc;stroke-width:1pt;stroke-opacity:1"
transform="scale(0.8)" />
</marker>
<marker
id="marker1984"
refX="5.0"
refY="3.0"
orient="auto-start-reverse">
<path
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1"
d="m 10,3 -10,3 0,-6 z"
id="path1982" />
</marker>
<marker
id="marker1920"
refX="5.0"
refY="3.0"
orient="auto-start-reverse">
<path
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1"
d="m 10,3 -10,3 0,-6 z"
id="path1918" />
</marker>
<marker
orient="auto"
refY="0.0"
refX="0.0"
id="marker1502"
style="overflow:visible">
<path
id="path1500"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(0.6) translate(0,0)" />
</marker>
<marker
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Sstart"
style="overflow:visible">
<path
id="path1050"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#bbbcbc;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(0.3) translate(-2.3,0)" />
</marker>
<marker
orient="auto"
refY="0.0"
refX="0.0"
id="marker1406"
style="overflow:visible">
<path
id="path1404"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#bbbcbc;stroke-width:1pt;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
transform="scale(0.4) translate(10,0)" />
</marker>
<marker
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Mend"
style="overflow:visible;">
<path
id="path1047"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#bbbcbc;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(0.6) rotate(180) translate(0,0)" />
</marker>
<marker
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Mstart"
style="overflow:visible">
<path
id="path1044"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#bbbcbc;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(0.6) translate(0,0)" />
</marker>
<marker
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Mstart"
style="overflow:visible">
<path
id="path1026"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#bbbcbc;stroke-width:1pt;stroke-opacity:1;fill:#bbbcbc;fill-opacity:1"
transform="scale(0.4) translate(10,0)" />
</marker>
<marker
orient="auto-start-reverse"
refY="3"
refX="5"
id="ExperimentalArrow-2">
refY="3.0"
refX="5.0"
id="ExperimentalArrow">
<path
id="path1273-1"
d="M 10,3 0,6 V 0 Z"
id="path1273"
d="m 10,3 -10,3 0,-6 z"
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1" />
</marker>
<marker
orient="auto-start-reverse"
refY="3"
refX="5"
id="ExperimentalArrow-3">
<path
id="path1273-6"
d="M 10,3 0,6 V 0 Z"
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1" />
</marker>
<marker
id="marker1984-1"
id="ExperimentalArrow-5"
refX="5"
refY="3"
orient="auto-start-reverse">
<path
inkscape:connector-curvature="0"
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1"
d="M 10,3 0,6 V 0 Z"
id="path1982-1" />
id="path1273-2" />
</marker>
<marker
orient="auto"
refY="0"
refX="0"
id="StopL-8"
style="overflow:visible">
id="ExperimentalArrow-2"
refX="5"
refY="3"
orient="auto-start-reverse">
<path
inkscape:connector-curvature="0"
id="path1189-1"
d="M 0,5.65 V -5.65"
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1"
d="M 10,3 0,6 V 0 Z"
id="path1273-1" />
</marker>
<marker
id="ExperimentalArrow-3"
refX="5"
refY="3"
orient="auto-start-reverse">
<path
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1"
d="M 10,3 0,6 V 0 Z"
id="path1273-6" />
</marker>
<marker
orient="auto-start-reverse"
refY="3"
refX="5"
id="marker1984-1">
<path
id="path1982-1"
d="M 10,3 0,6 V 0 Z"
style="fill:context-stroke;stroke:#bbbcbc;stroke-opacity:1"
inkscape:connector-curvature="0" />
</marker>
<marker
style="overflow:visible"
id="StopL-8"
refX="0"
refY="0"
orient="auto">
<path
transform="scale(0.8)"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#bbbcbc;stroke-width:1pt;stroke-opacity:1"
transform="scale(0.8)" />
d="M 0,5.65 V -5.65"
id="path1189-1"
inkscape:connector-curvature="0" />
</marker>
</defs>
<metadata
@@ -319,227 +319,207 @@
<g
id="layer1">
<path
inkscape:connector-curvature="0"
id="path963"
style="fill:#979797;fill-opacity:1;stroke:#979797;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 156.931,209.46621 156.11454,0.72523508"
style="fill:#979797;fill-opacity:1;stroke:#979797;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
id="path963"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path967"
d="m 26.520225,102.56968 101.609595,0.0638 v 0 0 0"
style="fill:none;stroke:#bbbcbc;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#bbbcbc;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 27.881686,115.27013 26.766659,0.0328 v 0 0 0"
id="path967-2" />
d="m 26.520225,170.56968 101.609595,0.0638 v 0 0 0"
id="path967"
inkscape:connector-curvature="0" />
<path
id="path967-2"
d="m 27.881686,183.27013 26.766659,0.0328 v 0 0 0"
style="fill:none;stroke:#bbbcbc;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<g
style="fill:#99cfff;fill-rule:evenodd;stroke:#002680;stroke-width:4;stroke-linejoin:round"
transform="matrix(0.26458333,0,0,0.26458333,36.848572,131.73977)"
id="g842"
transform="matrix(0.26458333,0,0,0.26458333,36.848572,63.739768)">
style="fill:#99cfff;fill-rule:evenodd;stroke:#002680;stroke-width:4;stroke-linejoin:round">
<rect
id="Rectangle-Copy"
x="11"
y="147"
height="48"
width="334"
height="48" />
y="147"
x="11"
id="Rectangle-Copy" />
<rect
id="Rectangle-Copy-2"
x="0"
y="199"
height="4"
width="356"
height="4" />
y="199"
x="0"
id="Rectangle-Copy-2" />
<polygon
id="Rectangle"
points="68,147 98,0 257.62107,0 287.62107,147 " />
points="257.62107,0 287.62107,147 68,147 98,0 "
id="Rectangle" />
<polygon
id="polygon840"
points="257.62107,147 287.62107,179 68,179 98,147 "
transform="matrix(1,0,0,-1,0,326)"
points="68,179 98,147 257.62107,147 287.62107,179 " />
id="polygon840" />
</g>
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#bbbcbc;stroke-width:0.506214;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 128.13064,169.64777 -0.94836,-79.838053 v 0"
id="path1004"
d="m 128.13064,101.64777 -0.94836,-79.838053 v 0"
style="fill:none;stroke:#bbbcbc;stroke-width:0.506214;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#bbbcbc;stroke-width:0.507232;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 7.7467941,90.012593 144.96042,89.468186 v 0 0"
id="path1006"
d="M 7.7467941,22.012593 144.96042,21.468186 v 0 0"
style="fill:none;stroke:#bbbcbc;stroke-width:0.507232;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#bbbcbc;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 81.767182,90.017085 V 100.08673"
id="path1012"
d="M 81.767182,22.017085 V 32.086727"
style="fill:none;stroke:#bbbcbc;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path1014"
d="m 31.419476,115.38155 -5.26e-4,69.84397 v 0"
style="fill:none;stroke:#bbbcbc;stroke-width:0.510365;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path1016"
d="M 14.545513,185.5762 141.91289,185.30405"
style="fill:none;stroke:#bbbcbc;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path1018"
style="fill:none;stroke:#bbbcbc;stroke-width:0.530934;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 169.07902,100.69655 32.94825,0.0636 v 0"
style="fill:none;stroke:#bbbcbc;stroke-width:0.530934;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
id="path1018"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#bbbcbc;stroke-width:0.420779;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:"
d="M 136.74199,21.332161 V 32.475182"
id="path1012-1" />
id="path1012-1"
d="M 136.74199,89.332161 V 100.47518"
style="fill:none;stroke:#bbbcbc;stroke-width:0.420779;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#bbbcbc;stroke-width:0.573405;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#StopL)"
d="m 8.1373094,90.089263 v 7.19921"
id="path1012-1-6"
d="m 8.1373094,22.089263 v 7.19921"
style="fill:none;stroke:#bbbcbc;stroke-width:0.573405;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#StopL)" />
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path3838"
style="fill:none;stroke:#bbbcbd;stroke-width:0.525286;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 209.62896,109.94961 h -40.55073 v 0"
style="fill:none;stroke:#bbbcbd;stroke-width:0.525286;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
id="path3838"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4058"
style="fill:none;stroke:#bbbcbc;stroke-width:0.517246;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 274.94556,100.96858 h 16.60132"
style="fill:none;stroke:#bbbcbc;stroke-width:0.517246;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
id="path4058"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4060"
style="fill:none;stroke:#bbbcbc;stroke-width:0.505291;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 278.21139,114.84836 H 291.2747"
style="fill:none;stroke:#bbbcbc;stroke-width:0.505291;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
id="path4060"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#bbbcbc;stroke-width:0.5132;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path1012-9"
d="m 290.73041,100.87214 v 14.2521"
id="path1012-9" />
style="fill:none;stroke:#bbbcbc;stroke-width:0.5132;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<g
style="fill:#99cfff;fill-rule:evenodd;stroke:#002680;stroke-width:4;stroke-linejoin:round"
transform="matrix(0.26458333,0,0,0.26458333,184.30533,62.410816)"
id="g918"
transform="matrix(0.26458333,0,0,0.26458333,184.30533,62.410816)">
style="fill:#99cfff;fill-rule:evenodd;stroke:#002680;stroke-width:4;stroke-linejoin:round">
<rect
id="Rectangle-Copy-5"
x="11"
y="147"
height="48"
width="334"
height="48" />
y="147"
x="11"
id="Rectangle-Copy-5" />
<rect
id="Rectangle-Copy-2-3"
x="0"
y="199"
height="4"
width="356"
height="4" />
y="199"
x="0"
id="Rectangle-Copy-2-3" />
<polygon
id="Rectangle-1"
points="257.62107,0 287.62107,147 68,147 98,0 " />
points="257.62107,0 287.62107,147 68,147 98,0 "
id="Rectangle-1" />
<polygon
id="polygon916"
points="257.62107,147 287.62107,179 68,179 98,147 "
transform="matrix(1,0,0,-1,0,326)"
points="257.62107,147 287.62107,179 68,179 98,147 " />
id="polygon916" />
</g>
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#bbbcbc;stroke-width:0.544692;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path1012-5"
d="M 178.87573,62.402301 V 100.34339"
id="path1012-5" />
style="fill:none;stroke:#bbbcbc;stroke-width:0.544692;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path6954"
style="fill:none;stroke:#bbbcbc;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 209.90111,62.050773 H 178.05927"
style="fill:none;stroke:#bbbcbc;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
id="path6954"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path7676"
style="fill:none;stroke:#bbbcbc;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 290.73042,115.10538 v 4.08228 0"
style="fill:none;stroke:#bbbcbc;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
id="path7676"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path7678"
style="fill:none;stroke:#bbbcbc;stroke-width:0.585901;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:"
d="M 172.07191,96.971722 V 109.67746"
style="fill:none;stroke:#bbbcbc;stroke-width:0.585901;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:" />
id="path7678"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path7680"
style="fill:none;stroke:#bbbcbc;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 172.07191,110.04689 v 8.33945"
style="fill:none;stroke:#bbbcbc;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
id="path7680"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path1012-1-6-1"
d="M 28.871798,89.809207 V 170.21125"
style="fill:none;stroke:#bbbcbc;stroke-width:0.510445;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 28.871798,21.809207 V 102.21125"
id="path1012-1-6-1" />
inkscape:connector-curvature="0" />
<path
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.299082px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 178.74528,61.891705 -1.99023,4.161391 h 3.98046 z"
id="path32784"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path32784"
d="m 178.74528,61.891705 -1.99023,4.161391 h 3.98046 z"
id="path32784-2"
d="m 81.78039,89.621142 -1.99023,4.16139 h 3.98046 z"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.299082px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.299082px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 81.78039,21.621142 -1.99023,4.16139 h 3.98046 z"
id="path32784-2"
inkscape:connector-curvature="0" />
<path
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.299082px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 28.948815,21.983004 -1.99023,4.16139 h 3.98046 z"
inkscape:connector-curvature="0"
id="path32784-6"
inkscape:connector-curvature="0" />
d="m 28.948815,89.983004 -1.99023,4.16139 h 3.98046 z"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.299082px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.299082px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 8.1418572,21.802077 -1.99023,4.16139 h 3.9804598 z"
inkscape:connector-curvature="0"
id="path32784-5"
inkscape:connector-curvature="0" />
d="m 8.1418572,89.802077 -1.99023,4.16139 h 3.9804598 z"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.299082px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.299082px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 31.481832,115.52385 -1.99023,4.16139 h 3.98046 z"
id="path32784-57"
inkscape:connector-curvature="0" />
<path
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.299082px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 290.75461,101.04944 -1.99023,4.16139 h 3.98046 z"
inkscape:connector-curvature="0"
id="path32784-51"
inkscape:connector-curvature="0" />
d="m 290.75461,101.04944 -1.99023,4.16139 h 3.98046 z"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.299082px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.299082px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 172.0645,109.91501 -1.99023,4.16139 h 3.98046 z"
inkscape:connector-curvature="0"
id="path32784-23"
inkscape:connector-curvature="0" />
d="m 172.0645,109.91501 -1.99023,4.16139 h 3.98046 z"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.299082px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.278896px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 81.961325,35.733683 -1.99023,-3.6186 h 3.98046 z"
inkscape:connector-curvature="0"
id="path32784-3"
d="m 81.961325,103.73368 -1.99023,-3.6186 h 3.98046 z"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.278896px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.278897px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 136.96407,103.64323 -1.99023,-3.6186 h 3.98046 z"
id="path32784-3-7"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path32784-3-7"
d="m 136.96407,35.643226 -1.99023,-3.6186 h 3.98046 z"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.278897px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path32784-3-73"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.278897px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 172.24542,100.41618 -1.99023,-3.618595 h 3.98046 z"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.278897px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
id="path32784-3-73"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path32784-3-2"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.278897px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 178.93983,100.41619 -1.99023,-3.6186 h 3.98046 z"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.278897px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
id="path32784-3-2"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path32784-3-70"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.278897px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 290.75462,114.89059 -1.99023,-3.6186 h 3.98046 z"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.278897px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
id="path32784-3-70"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.278897px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 127.93118,170.04456 -1.99023,-3.6186 h 3.98046 z"
id="path32784-3-5"
d="m 127.93118,102.04456 -1.99023,-3.618604 h 3.98046 z"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.278897px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path32784-3-24"
d="m 31.481836,185.27239 -1.99023,-3.6186 h 3.98046 z"
style="fill:#bbbcbc;fill-opacity:1;stroke:none;stroke-width:0.278897px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 20 KiB

@@ -4,5 +4,5 @@
"enabled": true,
"apiServerUrl": "http://localhost:9000/"
},
"allUIVisible": true
"allUIVisible": false
}
+1
View File
@@ -20,6 +20,7 @@
<body>
<app>
<img src="/assets/icons/png/bg.png" style="display:hidden">
<div id="loading-spinner"><i class="fa fa-circle-o-notch fa-spin"></i></div>
</app>
<script src="/dist/vendors~main.js" type="text/javascript"></script>
+2
View File
@@ -18,5 +18,7 @@ declare module server {
terminated: boolean;
running: boolean;
hasError: boolean;
category: string;
subCategory_1: string;
}
}
+8
View File
@@ -20,6 +20,7 @@ import Component from "vue-class-component";
import { Watch } from "vue-property-decorator";
import { UsersService } from "./services/usersService";
import { KeyboardHelper } from "./app_modules_thermo/components/KeyboardHelper";
import printGantt from "@/app_modules_thermo/processo/components/printProcesso.vue";
declare var cmsClient;
@@ -37,6 +38,7 @@ declare var cmsClient;
dashboard: Dashboard,
predashboard: PreDashboard,
alarmList,
printGantt
}
})
export default class app extends Vue {
@@ -64,6 +66,12 @@ export default class app extends Vue {
mounted() {
let ms = messageService;
window.oncontextmenu = function (event) {
event.preventDefault();
event.stopPropagation();
return false;
};
// if cms is connected
if (typeof cmsClient != "undefined")
this.HMIsrc = cmsClient.getScreenBase64();
+1
View File
@@ -18,6 +18,7 @@
<paddle></paddle>
<app-footer :class="{'blur':(applyBlur || applyBlurNc)}"></app-footer>
<print-gantt></print-gantt>
</div>
<modal-container containerName="modal-login" name="modal-login"></modal-container>
<keyboard></keyboard>
@@ -23,7 +23,7 @@
justify-content: center;
height: 100%;
font-family: "Work Sans";
font-size: 47px;
font-size: 40px;
font-weight: 500;
line-height: 1.01;
padding-right: 1rem;
@@ -11,7 +11,7 @@ export default class Combo extends Vue {
get options() {
let result: { id: number, text: string, anim: string }[] = [];
if (this.value.enumVal)
if (this.value && this.value.enumVal)
for (const key in this.value.enumVal) {
if (this.value.enumVal.hasOwnProperty(key)) {
const element = this.value.enumVal[key];
@@ -1,6 +1,10 @@
<template>
<div class="combo">
<div class="form" @click="showList" :class="{'error': value.status && value.status.hasError}">
<div
class="form"
@click="showList"
:class="{'error': value && value.status && value.status.hasError}"
>
{{currentValue}}
<i v-if="opened" class="fa fa-chevron-up" />
<i v-else class="fa fa-chevron-down" />
@@ -18,29 +18,43 @@ export default class Keyboard extends Vue {
@Prop()
value: string;
get Value() {
return this.actualValue.setpointHMI;
}
set Value(v: number) {
try {
let scale = Math.pow(10, this.actualValue.numDec);
this.actualValue.setpointHMI = Math.round(v * scale) / scale;
} catch{
this.actualValue.setpointHMI = v;
}
}
del() {
this.actualValue.setpointHMI = 0;
this.Value = 0;
}
canc() {
let temp = String(this.actualValue.setpointHMI);
this.actualValue.setpointHMI = Number(temp.slice(0, -1))
let temp = String(this.Value);
this.Value = Number(temp.slice(0, -1))
}
add(num: string) {
if (this.point) {
this.point += num;
this.actualValue.setpointHMI = Number(this.point)
this.Value = Number(this.point)
} else {
let temp = String(this.actualValue.setpointHMI);
let temp = String(this.Value);
temp += num;
this.actualValue.setpointHMI = Number(temp)
this.Value = Number(temp)
}
}
addpoint() {
if (!this.point) {
this.point = String(this.actualValue.setpointHMI);
this.point = String(this.Value);
this.point += ".";
}
}
@@ -29,6 +29,19 @@ export default class Numeric extends Vue {
focused: boolean = false;
get Value() {
return this.value.setpointHMI;
}
set Value(v: number) {
try {
let scale = Math.pow(10, this.value.numDec);
this.value.setpointHMI = Math.round(v * scale) / scale;
} catch {
this.value.setpointHMI = v;
}
}
onFocus() {
if (this.value && this.value.status && !this.value.status.enabled) return;
let rect = this.$el.getBoundingClientRect();
@@ -6,7 +6,7 @@
<input
type="number"
ref="input"
v-model.number="value.setpointHMI"
v-model.number="Value"
@focus="onFocus"
@blur="onBlur"
:id="id"
@@ -4,6 +4,7 @@ import { Prop } from 'vue-property-decorator';
import { Hub } from "@/services";
import Numeric from "./numeric";
import { unitOfTime } from "moment";
@Component({ name: "slider" })
export default class Slider extends Vue {
@@ -33,19 +34,29 @@ export default class Slider extends Vue {
this.value.setpointHMI = v;
}
get step() {
// var s = ((this.value.range.max - this.value.range.min) / (this.lines + 1));
// var m = Math.pow(10, this.decimal);
// return Math.round(s * m) / m
return 1;
};
@Prop({ default: .2 })
incrementingStep: number;
step: number = 1;
// get step() {
// var s = ((this.value.range.max - this.value.range.min) / (this.lines + 1));
// var m = Math.pow(10, this.decimal);
// return Math.round(s * m) / m
// return 1;
// };
mounted() {
this.step = 1 / Math.pow(10, this.value.numDec);
if (Number.isNaN(this.step)) this.step = 1;
}
startIncrement() {
if (!this.value.status.enabled) return;
this.incrementing = setInterval(() => {
var v = this.value.setpointHMI;
if (v < this.value.range.max) {
v += this.step;
v += Math.floor(this.step);
this.step += this.incrementingStep;
}
if (v > this.value.range.max) {
v = this.value.range.max;
@@ -59,7 +70,8 @@ export default class Slider extends Vue {
this.incrementing = setInterval(() => {
var v = this.value.setpointHMI;
if (v > this.value.range.min) {
v -= this.step;
v -= Math.floor(this.step);
this.step += this.incrementingStep;
}
if (v < this.value.range.min) {
v = this.value.range.min;
@@ -74,7 +86,7 @@ export default class Slider extends Vue {
clearInterval(this.incrementing);
this.incrementing = 0;
this.step = 1;
};
@@ -1,7 +1,13 @@
<template>
<div class="slider-container">
<div class="slider">
<button @mousedown="startDecrement()" @mouseup="confirm()" @mouseout="confirm()">
<button
@mousedown="startDecrement()"
v-on:touchstart="startDecrement()"
v-on:touchend="confirm()"
@mouseup="confirm()"
@mouseout="confirm()"
>
<img src="assets/icons/png/min.png" />
</button>
<div class="control">
@@ -21,7 +27,13 @@
<small>{{`${this.value.range.max} ${this.value.unitMeasure}`}}</small>
</div>
</div>
<button @mousedown="startIncrement()" @mouseup="confirm()" @mouseout="confirm()">
<button
@mousedown="startIncrement()"
v-on:touchstart="startIncrement()"
v-on:touchend="confirm()"
@mouseup="confirm()"
@mouseout="confirm()"
>
<img src="assets/icons/png/max.png" />
</button>
</div>
@@ -40,5 +52,13 @@
justify-items: center;
width: 100%;
}
input[type="range"] {
pointer-events: none;
}
input[type="range"]::-webkit-slider-thumb {
pointer-events: auto;
}
</style>
<script lang="ts" src="./slider.ts"></script>
@@ -4,7 +4,7 @@ import { Prop, Watch } from 'vue-property-decorator';
import { messageService } from '@/_base';
import AppRibbon from "@/components/app-ribbon.vue";
import { alarmList } from "@/app_modules/alarms";
import { AppModel, appModelActions } from '@/store';
import { AppModel, appModelActions, store } from '@/store';
import { getColorFromName, isDarkColor } from "@/_base/utils";
import ArchInterface from "../components/arch-interface/arch-interface.vue";
import gauge from "./base-components/gauge.vue";
@@ -12,6 +12,8 @@ import { prodService } from '@/services/prodService';
import moment from 'moment';
import stats from "./base-components/stats.vue";
import hitem from "./base-components/item.vue";
import { Hub } from '@/services';
import { SoftKeysConfigurationModel } from '@/store/machineInfo.store';
@Component({
components: {
@@ -25,7 +27,6 @@ import hitem from "./base-components/item.vue";
})
export default class Dashboard extends Vue {
get panel() {
return (this.$store.state as AppModel).prod.panel;
}
@@ -54,7 +55,7 @@ export default class Dashboard extends Vue {
}
get remainingTime() {
return this.endEstimation.diff(this.now);
return Math.max(this.endEstimation.diff(this.now), 0);
}
get currentUser() {
@@ -65,6 +66,18 @@ export default class Dashboard extends Vue {
return (this.$store.state as AppModel).machineInfo.cmsConnectReady;
}
get softKeys(): { [id: number]: SoftKeysConfigurationModel[] } {
return store.state.machineInfo.softKeys as { [id: number]: SoftKeysConfigurationModel[] };
}
get allSoftKeys(): SoftKeysConfigurationModel[] {
var result = [];
for (const key in this.softKeys) {
const element = this.softKeys[key];
result.push(...element);
}
return result;
}
loading = false;
async loadMore() {
@@ -80,11 +93,11 @@ export default class Dashboard extends Vue {
getColor(nome, cognome) {
return getColorFromName(nome, cognome);
}
isDarkColor(color) {
return isDarkColor(color);
}
async mounted() {
prodService.GetProdPanel();
@@ -95,7 +108,6 @@ export default class Dashboard extends Vue {
}
public get ribbonStatus(): ribbonStatusEnum {
// Controllo se ci sono allarmi
let s = this.$store.state as AppModel;
@@ -103,7 +115,6 @@ export default class Dashboard extends Vue {
if (s.alarms.warnings.length > 0) return ribbonStatusEnum.Warning;
if (s.process.running) return ribbonStatusEnum.Working;
return ribbonStatusEnum.Idle;
}
public get alarmTitle() {
@@ -120,7 +131,6 @@ export default class Dashboard extends Vue {
default:
return "";
}
}
public get alarmCount() {
@@ -148,6 +158,13 @@ export default class Dashboard extends Vue {
}
}
sendSoftKey(id: string) {
debugger
var sk = this.allSoftKeys.find(s => s.refCallParam == id);
if (sk)
Hub.Current.sendUserSoftKey(sk.id);
}
public sendMessage(name: string) {
messageService.publishToChannel(name);
}
@@ -155,7 +172,6 @@ export default class Dashboard extends Vue {
close() {
appModelActions.ShowDashboard(this.$store);
};
}
enum ribbonStatusEnum {
@@ -99,7 +99,12 @@
</div>
<div class="end">
<small>{{'dashboard-timing-end' | localize('fine')}}</small>
<time v-if="panel.stimaDurata">~{{endEstimation | date('HH:mm')}}</time>
<time v-if="panel.stimaDurata">
<span>~{{endEstimation | date('HH:mm')}}</span>
<small
style="text-transform:lowercase"
>+{{Math.floor(remainingTime /1000 / 3600 /24)}} {{'remainging__days' | localize("gg")}}</small>
</time>
<time v-else>--:--</time>
</div>
</div>
@@ -107,14 +112,14 @@
<div class="setpoint">
<img src="assets/icons/png/inv.png" />
<label>{{panel.tempAct}}°C</label>
<button>
<button @click="sendSoftKey('dash_setpoint_minus')">
<i class="fa fa-minus"></i>
</button>
<div>
<small>{{'dashboard-setpoint' | localize('set point')}}</small>
<span>{{panel.tempSetpoint}}°C</span>
</div>
<button>
<button @click="sendSoftKey('dash_setpoint_plus')">
<i class="fa fa-plus"></i>
</button>
</div>
@@ -124,7 +129,9 @@
<gauge></gauge>
<div class="remaining_time">
<small>{{'dashboard-remaining-time' | localize('tempo rimanente')}}</small>
<time v-if="panel.stimaDurata">{{remainingTime | date('HH:mm:ss')}}</time>
<time
v-if="panel.stimaDurata"
>{{Math.floor(remainingTime /1000 / 3600)}}:{{remainingTime | date('mm:ss')}}</time>
<time v-else>--:--:--</time>
</div>
</div>
@@ -4,6 +4,19 @@ import { Prop, InjectReactive } from 'vue-property-decorator';
import { IGanttOptions } from './gantt';
import { store } from '@/store';
import { RecipeGetters } from '@/store/recipe.store';
import { ModalHelper } from '@/components/modals';
import ShowRiscaldamentoInfo from "@/app_modules_thermo/setup/riscaldi/components/show-riscaldi-info.vue";
import ShowFormatoInfo from "@/app_modules_thermo/setup/formato/components/show-formato-info.vue";
import ShowPirometroInfo from "@/app_modules_thermo/setup/pirometro/components/show-pirometro-info.vue";
import ShowCicloInfo from "@/app_modules_thermo/setup/ciclo/components/show-ciclo-info.vue";
import ShowRaffreddamentoInfo from "@/app_modules_thermo/setup/raffreddamento/components/show-raffreddamento-info.vue";
import ShowControstampoInfo from "@/app_modules_thermo/setup/controstampo_setup/components/show-controstampo-info.vue";
import ShowQuoteVelocitaInfo from "@/app_modules_thermo/setup/quote-velocita/components/show-quote-velocita-info.vue";
import ShowEstrazioneInfo from "@/app_modules_thermo/setup/estrazione/components/show-estrazione-info.vue";
import ShowVuotoInfo from "@/app_modules_thermo/setup/vuoto/show-vuoto-info.vue";
import ShowImbutituraInfo from "@/app_modules_thermo/setup/imbutitura/show-imbutitura-info.vue";
import ShowOpzioniInfo from "@/app_modules_thermo/setup/opzioni/show-opzioni-info.vue";
@Component({})
export default class GanttComponent extends Vue {
@@ -71,6 +84,53 @@ export default class GanttComponent extends Vue {
return this.showStatus ? this.ganttOptions.block_status_minDuration : 0;
}
openModal() {
if (this.value.category)
switch (this.value.category.toLowerCase()) {
case "general": this.showModalAtStep(0, this.value.subCategory_1); break;
case "positions": this.showModalAtStep(1, this.value.subCategory_1); break;
case "cycle": this.showModalAtStep(2, this.value.subCategory_1); break;
case "heats": this.showModalAtStep(3, this.value.subCategory_1); break;
case "pyrometer": this.showModalAtStep(4, this.value.subCategory_1); break;
case "drawing": this.showModalAtStep(5, this.value.subCategory_1); break;
case "upperplate": this.showModalAtStep(6, this.value.subCategory_1); break;
case "cooling": this.showModalAtStep(7, this.value.subCategory_1); break;
case "vacuum": this.showModalAtStep(8, this.value.subCategory_1); break;
case "extraction": this.showModalAtStep(9, this.value.subCategory_1); break;
case "options": this.showModalAtStep(10, this.value.subCategory_1); break;
}
}
async showModalAtStep(step: number, subcategory: string) {
try {
let next = await this.showModalStep(step, subcategory);
if (next == null) return;
this.showModalAtStep(step + next, null);
} catch {
}
}
showModalStep(step: number, subcategory: string): Promise<number> {
switch (step) {
case 0: return ModalHelper.ShowModalAsync(ShowFormatoInfo, { subcategory });
case 1: return ModalHelper.ShowModalAsync(ShowQuoteVelocitaInfo, { subcategory });
case 2: return ModalHelper.ShowModalAsync(ShowCicloInfo, { subcategory });
case 3: return ModalHelper.ShowModalAsync(ShowRiscaldamentoInfo, { subcategory });
case 4: return ModalHelper.ShowModalAsync(ShowPirometroInfo, { subcategory });
case 5: return ModalHelper.ShowModalAsync(ShowImbutituraInfo, { subcategory });
case 6: return ModalHelper.ShowModalAsync(ShowControstampoInfo, { subcategory });
case 7: return ModalHelper.ShowModalAsync(ShowRaffreddamentoInfo, { subcategory });
case 8: return ModalHelper.ShowModalAsync(ShowVuotoInfo, { subcategory });
case 9: return ModalHelper.ShowModalAsync(ShowEstrazioneInfo, { subcategory });
case 10: return ModalHelper.ShowModalAsync(ShowOpzioniInfo, { subcategory });
// case 11: return ModalHelper.ShowModalAsync(AvvioProduzione);
}
return null;
}
// mounted() {
// this.value.showDelay = true;
// }
@@ -36,7 +36,7 @@
x="0"
y="0"
>
<div class="body-header">{{value.label | localize(value.label)}}</div>
<div class="body-header" @click="openModal()">{{value.label | localize(value.label)}}</div>
</foreignObject>
<foreignObject
:width="(duration - (showStatus && recipeValue?statusDuration:0)) * ganttOptions.secondSize"
@@ -149,7 +149,7 @@
</foreignObject>
</g>
<g v-if="value.showDelay">
<g v-if="value.showDelay && !ganttOptions.printing">
<line x1="0" y1="0" y2="0" :x2="actualDelay * ganttOptions.secondSize" class="progress-line" />
<foreignObject
width="30"
@@ -161,7 +161,10 @@
</foreignObject>
</g>
<g :transform="`translate(${delayDuration * ganttOptions.secondSize} 0)`">
<g
:transform="`translate(${delayDuration * ganttOptions.secondSize} 0)`"
v-if="!ganttOptions.printing"
>
<line
x1="0"
y1="0"
@@ -32,6 +32,14 @@ export default class GanttRow extends Vue {
return Array.from(this.blocks.values()).filter(i => i.section == this.section).sort((a, b) => a.priority - b.priority);
}
get maxVerticalPosition() {
return Math.max(...this.blocks.map(b => this.verticalPosition(b)))
}
get maxBlockPosition() {
return Math.max(...this.blocks.map(b => this.startPosition(b)))
}
startPosition(block: server.Modblock) {
return blockStartPosition(block, this.blocks, this.ganttOptions) * this.ganttOptions.secondSize;
}
@@ -65,7 +73,8 @@ export default class GanttRow extends Vue {
// cerco la prima delle righe disponibili che avrebbero posto per il mio blocco
// una riga è disponibile se non ci sono blocchi che occupano lo spazio che mi servirebbe
let myrow = rows.filter(r => r.filter(b => (b.from <= myStartPosition && b.to >= myStartPosition) || (b.from <= myEndPosition && b.to >= myEndPosition)).length == 0).shift();
let myrow = rows.filter(r => r.filter(b => (b.from <= myStartPosition && b.to >= myStartPosition) || (b.from <= myEndPosition && b.to >= myEndPosition) ||
(myStartPosition <= b.from && myEndPosition >= b.from) || (myStartPosition <= b.to && myEndPosition >= b.to)).length == 0).shift();
// se non ho trovato una riga allora non c'è posto oppure non ci sono righe..
// aggiungo eventualmente una nuova riga
@@ -120,6 +129,7 @@ function blockDuration(block: server.Modblock, options: IGanttOptions, includeDe
duration += Math.max(minduration, block.terminated ? 0 : block.estimatedDuration, block.actualDuration);
if (block.idParam > 0 && includeDelay)
duration += options.block_status_minDuration;
@@ -4,6 +4,24 @@ import moment from "moment";
import ganttHeader from "./gantt-header.vue";
import ganttRow from "./gantt-row.vue"
import timeLine from "./timeline.vue";
import { recipeService } from "@/services/recipeService";
import { store, AppModel } from "@/store";
var ContainerElements = ["svg", "g", "foreignobject"];
var RelevantStyles = {
"rect": ["fill", "stroke", "stroke-width", "rx", "ry"],
"path": ["fill", "stroke", "stroke-width"],
"circle": ["fill", "stroke", "stroke-width"],
"line": ["stroke", "stroke-width"],
"text": ["fill", "font-size", "text-anchor"],
"polygon": ["stroke", "fill"],
"foreignobject": [],
"div": [
"align-items", "justify-content", "font-family", "flex-flow", "font-size",
"height", "padding", "color", "display", "width", "border-radius",
"background-color", "transform"],
"span": ["letter-spacing", "text-transform", "background-color"]
};
@Component({
components: {
@@ -18,12 +36,71 @@ export default class Gantt extends Vue {
padX: number = 0;
padY: number = 0;
get panel() {
return (this.$store.state as AppModel).prod.panel;
}
get ganttHeight() {
return (this.$refs.section1 as any).rowHeight +
(this.$refs.section2 as any).rowHeight +
(this.$refs.section3 as any).rowHeight;
}
public print() {
this.ganttOptions.printing = true;
this.$nextTick(() => {
var oDOM = (this.$refs.mainContainer as SVGElement).cloneNode(true)
this.exportSVGWithStyle(oDOM, this.$refs.mainContainer)
var data = new XMLSerializer().serializeToString(oDOM);
var DOMURL = (window.URL || window.webkitURL);
var svgBlob = new Blob([data], { type: 'image/svg+xml;charset=utf-8' });
// var url = DOMURL.createObjectURL(svgBlob);
recipeService.UploadImage(svgBlob, this.panel.nomeRicetta.replace('.rcp', '') + ".svg");
this.ganttOptions.printing = false;
// window.open(url, '_blank')
});
}
exportSVGWithStyle(ParentNode, OrigData) {
var Children = ParentNode.childNodes;
var OrigChildDat = OrigData.childNodes;
for (var cd = 0; cd < Children.length; cd++) {
var Child = Children[cd];
var TagName = (Child.tagName as string)?.toLowerCase();
if (ContainerElements.indexOf(TagName) != -1) {
this.exportSVGWithStyle(Child, OrigChildDat[cd])
} else if (TagName in RelevantStyles) {
var StyleDef = window.getComputedStyle(OrigChildDat[cd]);
var StyleString = "";
for (var st = 0; st < RelevantStyles[TagName].length; st++) {
StyleString += RelevantStyles[TagName][st] + ":" + StyleDef.getPropertyValue(RelevantStyles[TagName][st]) + "; ";
}
Child.setAttribute("style", StyleString);
}
}
}
get PadX() {
let w = ((this.$refs.mainContainer as any)?.clientWidth ?? 0) / 3;
if (this.follow && w && this.currentTime * this.ganttOptions.secondSize > w)
return -(this.currentTime * this.ganttOptions.secondSize - w);
return this.padX;
}
set PadX(value: number) {
if (!this.follow)
this.padX = value;
@@ -69,7 +146,8 @@ export default class Gantt extends Vue {
block_body_Vacuum_minDuration: 5,
block_body_Cooling_minDuration: 10,
block_body_Extraction_minDuration: 5,
block_padding: 0.01
block_padding: 0.01,
printing: false
};
@Prop({ default: 0 })
@@ -179,4 +257,5 @@ export interface IGanttOptions {
block_body_Cooling_minDuration: number;
block_body_Extraction_minDuration: number;
block_padding: number;
printing: boolean;
}
@@ -4,7 +4,7 @@
ref="mainContainer"
preserveAspectRation="xMinYMax"
width="100%"
height="100%"
:height="ganttOptions.printing ? `${ganttHeight}px` : '100%'"
@mousemove.capture="doPan"
v-on:touchmove="doPan"
@mousedown="startPan"
@@ -55,7 +55,7 @@
</g>
<gantt-header :padding-horizontal="PadX " :zoom-factor="zoomFactor" />
<time-line
v-if="!!getRowHeight($refs.section1) && !!getRowHeight($refs.section2)"
v-if="!!getRowHeight($refs.section1) && !!getRowHeight($refs.section2) && !ganttOptions.printing"
:padding-horizontal="PadX"
:zoom-factor="zoomFactor"
:speed="1"
@@ -1,15 +1,13 @@
<template>
<svg class="timeline">
<g :transform="`translate(${ paddingHorizontal} 0)`" class="pad">
<g :transform="`scale(${zoomFactor} 1)`">
<g :transform="`scale(${zoomFactor} 1)`">
<g :transform="`translate(${ paddingHorizontal} 0)`" class="pad">
<g
:transform="`translate(${position} 0)`"
:style="position>20?`transition: transform ${speed}s linear`:''"
>
<g :transform="`scale(${2-zoomFactor} 1)`">
<path class="arrow" d="M 0 0 L 30 0 L 15 24 Z" />
<line x1="15" y1="24" x2="15" :y2="lineHeight" />
</g>
<path class="arrow" d="M 0 0 L 30 0 L 15 24 Z" />
<line x1="15" y1="24" x2="15" :y2="lineHeight" />
</g>
</g>
</g>
@@ -0,0 +1,23 @@
import Vue from "vue";
import Component from "vue-class-component";
import gantt from "./gantt/gantt.vue";
import { store } from "@/store";
import { messageService } from "@/_base";
@Component({
components: {
gantt
}
})
export default class PrintProcesso extends Vue {
get blocks(): server.Modblock[] {
return store.state.modules.blocks;
}
mounted() {
messageService.subscribeToChannel("print", () => {
(this.$refs.gantt as any).print();
})
}
}
@@ -0,0 +1,6 @@
<template>
<div class="printContainer">
<gantt ref="gantt" v-if="blocks" :blocks="blocks" :zoom-factor="1"></gantt>
</div>
</template>
<script src="./printProcesso.ts" lang="ts">
@@ -19,7 +19,9 @@
@checkChanged="softKeyChanged(b.id, b.operatorConfirmationNeeded)"
></soft-key>
</template>
<label><span v-if="tot">{{actual}}/{{tot}}</span></label>
<label>
<span v-if="tot">{{actual}}/{{tot}}</span>
</label>
</div>
<gantt
ref="gantt"
@@ -4,13 +4,14 @@ import { Prop } from "vue-property-decorator";
import { Deferred } from "@/services";
import { Modal, ModalHelper } from "@/components/modals";
import { messageService } from "@/_base";
import { recipeService } from "@/services/recipeService";
@Component({ components: { modal: Modal } })
export default class Notes extends Vue {
@Prop()
deferred: Deferred<string>;
@Prop()
value: string;
note: string = null;
@@ -21,6 +22,10 @@ export default class Notes extends Vue {
this.note = value;
}
async mounted() {
this.Note = await recipeService.GetNote();
}
save(value: string) {
this.deferred.resolve(this.Note);
ModalHelper.HideModal();
@@ -3,7 +3,7 @@ import { Modal, ModalHelper } from "@/components/modals";
import { Factory, messageService, awaiter } from "@/_base";
import Component from "vue-class-component";
import { Prop } from 'vue-property-decorator';
import { appModelActions } from "@/store/app.store";
import { appModelActions, store } from "@/store/app.store";
import { prodService } from "@/services/prodService";
@Component({
@@ -13,7 +13,7 @@ import { prodService } from "@/services/prodService";
})
export default class AvvioProduzione extends Vue {
enabling: boolean = true;
newjob: boolean = true;
pieces: Recipe.IValue = {
setpointHMI: 0,
@@ -25,13 +25,27 @@ export default class AvvioProduzione extends Vue {
}
} as Recipe.IValue;
warmuppieces: Recipe.IValue = {
setpointHMI: 0,
range: { min: 0, max: 999999 },
status: {
enabled: true,
hasError: false,
visible: true
}
} as Recipe.IValue;
annulla() {
ModalHelper.HideModal();
};
get prod() { return store.state.prod.panel }
showDashboard() {
prodService.Start(this.pieces.setpointHMI);
prodService.Start(this.pieces.setpointHMI, this.newjob, this.warmuppieces.setpointHMI);
ModalHelper.HideModal();
appModelActions.ShowDashboard(this.$store);
@@ -53,4 +67,8 @@ export default class AvvioProduzione extends Vue {
ModalHelper.HideModal();
}
mounted() {
this.pieces.setpointHMI = this.prod.numTarget;
}
}
@@ -11,13 +11,36 @@
</div>
<section>
<article>
<div class="input-area mb-10">
<label>{{'enabling'|localize('Settaggio numero pezzi')}}</label>
<toggle-button v-model="enabling"></toggle-button>
<div class="input-area mb-10" style="margin:auto">
<label>{{'new'|localize('Nuova produzione')}}</label>
<toggle-button v-model="newjob"></toggle-button>
</div>
<div class="input-area" v-if="enabling">
<label>{{'mock_pieces'|localize('Numero pezzi')}}</label>
<numeric v-model="pieces" :keyboardPosition="'bottom'" />
<div class="box mt-10">
<div class="header">
<label>{{'warmup_cycles' | localize("Preriscaldo")}}</label>
</div>
<div class="body">
<div class="input-area mb-10">
<label>{{'warmup_cycles_pieces'|localize('Cicli preriscaldo')}}</label>
<numeric v-model="warmuppieces" :keyboardPosition="'bottom'" />
</div>
</div>
</div>
<div class="box mt-10">
<div class="header">
<label>{{'production_management' | localize("Gestione produzione")}}</label>
</div>
<article class="body">
<div class="input-area mb-10">
<label>{{'production_enabling'|localize('Modifica numero pezzi')}}</label>
<toggle-button v-model="pieces.status.enabled"></toggle-button>
</div>
<div class="input-area mb-10">
<label style="flex:1;">{{'mock_pieces'|localize('Numero pezzi')}}</label>
<label>{{prod.numDone}}/</label>
<numeric v-model="pieces" :keyboardPosition="'bottom'" />
</div>
</article>
</div>
</article>
</section>
@@ -16,11 +16,19 @@ import { debounce } from '@/_base/debounce';
export default class ShowCicloInfo extends Vue {
recipe: Recipe.IRecipe = this.$store.getters.getCurrent();
show: number = 0;
show: string = 'forming';
@Prop()
deferred: Deferred<boolean>;
@Prop()
value: string;
mounted() {
if (this.value)
this.show = this.value;
}
annulla() {
recipeService.Cancel();
// ModalHelper.HideModal();
@@ -79,13 +87,17 @@ export default class ShowCicloInfo extends Vue {
const el = this.payload[key] as Recipe.IValue;
if (el.setpointHMI != el.setpointPLC) result = true;
}
for (const key in store.state.warmers.channels) {
const el = store.state.warmers.channels[key];
if (el.setpointHMI != el.setpointPLC) result = true;
}
return result;
}
hasEnabledFields(...fields: string[]) {
let result = false;
for (const field of fields) {
if ((this.recipe[field] as Recipe.IValue).status.enabled) result = true;
if ((this.recipe[field] as Recipe.IValue).status.visible) result = true;
}
return result;
}
@@ -2,10 +2,13 @@
<div class="setup">
<modal type="ciclo-info">
<div class="tab-header" slot="header-buttons">
<button :class="{'active':show==0}" @click="show=0">{{'cycle' | localize('Ciclo di formatura')}}</button>
<button
:class="{'active':show==1}"
@click="show=1"
:class="{'active':show=='forming'}"
@click="show='forming'"
>{{'cycle' | localize('Ciclo di formatura')}}</button>
<button
:class="{'active':show=='loader'}"
@click="show='loader'"
v-if="isLoaderEnabled()"
>{{'loader' | localize('Caricatore')}}</button>
</div>
@@ -14,8 +17,8 @@
<i class="fa fa-remove"></i>
</button>
</div>
<cicloformatura v-if="show==0" :recipe="recipe"></cicloformatura>
<caricatore v-if="show==1" :recipe="recipe"></caricatore>
<cicloformatura v-if="show=='forming'" :recipe="recipe"></cicloformatura>
<caricatore v-if="show=='loader'" :recipe="recipe"></caricatore>
<footer>
<button
class="btn"
@@ -15,7 +15,7 @@ import ShowEstrazioneInfo from "@/app_modules_thermo/setup/estrazione/components
import ShowVuotoInfo from "@/app_modules_thermo/setup/vuoto/show-vuoto-info.vue";
import ShowImbutituraInfo from "@/app_modules_thermo/setup/imbutitura/show-imbutitura-info.vue";
import ShowOpzioniInfo from "@/app_modules_thermo/setup/opzioni/show-opzioni-info.vue";
import AvvioProduzione from "@/app_modules_thermo/setup/avvio-produzione/avvio-produzione.vue";
// import AvvioProduzione from "@/app_modules_thermo/setup/avvio-produzione/avvio-produzione.vue";
import { store } from '@/store';
@@ -54,7 +54,7 @@ export default class Setup extends Vue {
case 8: return ModalHelper.ShowModalAsync(ShowVuotoInfo);
case 9: return ModalHelper.ShowModalAsync(ShowEstrazioneInfo);
case 10: return ModalHelper.ShowModalAsync(ShowOpzioniInfo);
case 11: return ModalHelper.ShowModalAsync(AvvioProduzione);
// case 11: return ModalHelper.ShowModalAsync(AvvioProduzione);
}
return null;
@@ -79,9 +79,9 @@
:status="overview.options"
></setup-button>
<div class="setup-play" @click="showModalAtStep(11);">
<!-- <div class="setup-play" @click="showModalAtStep(11);">
<img class="dim" src="assets/icons/svg/setup-play.svg" />
</div>
</div>-->
</div>
</modal>
</div>
@@ -27,11 +27,19 @@ import { debounce } from '@/_base/debounce';
export default class ShowControstampoInfo extends Vue {
recipe: Recipe.IRecipe = this.$store.getters.getCurrent();
show: number = 0;
show: string = 'cycle';
@Prop()
deferred: Deferred<boolean>;
@Prop()
value: string;
mounted() {
if (this.value)
this.show = this.value;
}
annulla() {
recipeService.Cancel();
// ModalHelper.HideModal();
@@ -94,13 +102,17 @@ export default class ShowControstampoInfo extends Vue {
const el = this.payload[key] as Recipe.IValue;
if (el.setpointHMI != el.setpointPLC) result = true;
}
for (const key in store.state.warmers.channels) {
const el = store.state.warmers.channels[key];
if (el.setpointHMI != el.setpointPLC) result = true;
}
return result;
}
hasEnabledFields(...fields: string[]) {
let result = false;
for (const field of fields) {
if ((this.recipe[field] as Recipe.IValue).status.enabled) result = true;
if ((this.recipe[field] as Recipe.IValue).status.visible) result = true;
}
return result;
}
@@ -3,23 +3,23 @@
<modal type="controstamposetup-info">
<div class="tab-header" slot="header-buttons">
<button
:class="{'active':show == 0}"
@click="show=0"
:class="{'active':show == 'cycle'}"
@click="show='cycle'"
v-if="isCycleEnabled()"
>{{'upperplate_cycle' |localize('Ciclo controstampo')}}</button>
<button
:class="{'active':show == 1}"
@click="show=1"
:class="{'active':show == 'air'}"
@click="show='air'"
v-if="isAirEnabled()"
>{{'upperplate_air' |localize('Aria controstampo')}}</button>
<button
:class="{'active':show == 2}"
@click="show=2"
:class="{'active':show == 'vacuum'}"
@click="show='vacuum'"
v-if="isVacuumEnabled()"
>{{'upperplate_vacuum' |localize('Vuoto controstampo')}}</button>
<button
:class="{'active':show == 3}"
@click="show=3"
:class="{'active':show == 'extraction'}"
@click="show='extraction'"
v-if="isExtractionEnabled()"
>{{'upperplate_extraction' |localize('Estrazione controstampo')}}</button>
</div>
@@ -28,10 +28,10 @@
<i class="fa fa-remove"></i>
</button>
</div>
<ciclocontrostampo v-if="show==0" :recipe="recipe"></ciclocontrostampo>
<ariacontrostampo v-if="show==1" :recipe="recipe"></ariacontrostampo>
<vuotocontrostampo v-if="show==2" :recipe="recipe"></vuotocontrostampo>
<estrazionecontrostampo v-if="show==3" :recipe="recipe"></estrazionecontrostampo>
<ciclocontrostampo v-if="show=='cycle'" :recipe="recipe"></ciclocontrostampo>
<ariacontrostampo v-if="show=='air'" :recipe="recipe"></ariacontrostampo>
<vuotocontrostampo v-if="show=='vacuum'" :recipe="recipe"></vuotocontrostampo>
<estrazionecontrostampo v-if="show=='extraction'" :recipe="recipe"></estrazionecontrostampo>
<footer>
<button
class="btn"
@@ -74,13 +74,17 @@ export default class ShowEstrazioneInfo extends Vue {
const el = this.payload[key] as Recipe.IValue;
if (el.setpointHMI != el.setpointPLC) result = true;
}
for (const key in store.state.warmers.channels) {
const el = store.state.warmers.channels[key];
if (el.setpointHMI != el.setpointPLC) result = true;
}
return result;
}
hasEnabledFields(...fields: string[]) {
let result = false;
for (const field of fields) {
if ((this.recipe[field] as Recipe.IValue).status.enabled) result = true;
if ((this.recipe[field] as Recipe.IValue).status.visible) result = true;
}
return result;
}
@@ -4,7 +4,7 @@
<div class="borded_label" id="quota1" v-focus-on:general_sizes_upperplate_max_height>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_upperplate_max_height.setpointHMI}}</span>
<span>{{recipe.general_sizes_upperplate_max_height.valueAct}}</span>
<small>{{recipe.general_sizes_upperplate_max_height.unitMeasure}}</small>
</div>
</div>
@@ -4,14 +4,14 @@
<div class="borded_label" id="quota1" v-focus-on:general_sizes_frame_dim_y>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_frame_dim_y.setpointHMI}}</span>
<span>{{recipe.general_sizes_frame_dim_y.valueAct}}</span>
<small>{{recipe.general_sizes_frame_dim_y.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota2" v-focus-on:general_sizes_frame_dim_x>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_frame_dim_x.setpointHMI}}</span>
<span>{{recipe.general_sizes_frame_dim_x.valueAct}}</span>
<small>{{recipe.general_sizes_frame_dim_x.unitMeasure}}</small>
</div>
</div>
@@ -4,21 +4,21 @@
<div class="borded_label" id="quota1" v-focus-on:general_sizes_sheet_dim_x>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_sheet_dim_x.setpointHMI}}</span>
<span>{{recipe.general_sizes_sheet_dim_x.valueAct}}</span>
<small>{{recipe.general_sizes_sheet_dim_x.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota2" v-focus-on:general_sizes_sheet_dim_y>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_sheet_dim_y.setpointHMI}}</span>
<span>{{recipe.general_sizes_sheet_dim_y.valueAct}}</span>
<small>{{recipe.general_sizes_sheet_dim_y.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota3" v-focus-on:general_sizes_sheet_thickness>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_sheet_thickness.setpointHMI}}</span>
<span>{{recipe.general_sizes_sheet_thickness.valueAct}}</span>
<small>{{recipe.general_sizes_sheet_thickness.unitMeasure}}</small>
</div>
</div>
@@ -4,14 +4,14 @@
<div class="borded_label" id="quota1" v-focus-on:general_sizes_plate_dim_y>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_plate_dim_y.setpointHMI}}</span>
<span>{{recipe.general_sizes_plate_dim_y.valueAct}}</span>
<small>{{recipe.general_sizes_plate_dim_y.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota2" v-focus-on:general_sizes_plate_dim_x>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_plate_dim_x.setpointHMI}}</span>
<span>{{recipe.general_sizes_plate_dim_x.valueAct}}</span>
<small>{{recipe.general_sizes_plate_dim_x.unitMeasure}}</small>
</div>
</div>
@@ -4,35 +4,35 @@
<div class="borded_label" id="quota1" v-focus-on:general_sizes_mould_dim_x>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_mould_dim_x.setpointHMI}}</span>
<span>{{recipe.general_sizes_mould_dim_x.valueAct}}</span>
<small>{{recipe.general_sizes_mould_dim_x.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota2" v-focus-on:general_sizes_mould_dim_y>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_mould_dim_y.setpointHMI}}</span>
<span>{{recipe.general_sizes_mould_dim_y.valueAct}}</span>
<small>{{recipe.general_sizes_mould_dim_y.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota3" v-focus-on:general_sizes_mould_max_height>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_mould_max_height.setpointHMI}}</span>
<span>{{recipe.general_sizes_mould_max_height.valueAct}}</span>
<small>{{recipe.general_sizes_mould_max_height.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota4" v-focus-on:general_sizes_mould_base_height>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_mould_base_height.setpointHMI}}</span>
<span>{{recipe.general_sizes_mould_base_height.valueAct}}</span>
<small>{{recipe.general_sizes_mould_base_height.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota5" v-focus-on:general_sizes_mould_min_height>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_mould_min_height.setpointHMI}}</span>
<span>{{recipe.general_sizes_mould_min_height.valueAct}}</span>
<small>{{recipe.general_sizes_mould_min_height.unitMeasure}}</small>
</div>
</div>
@@ -101,6 +101,10 @@ export default class ShowFormatoInfo extends Vue {
const el = this.payload[key] as Recipe.IValue;
if (el.setpointHMI != el.setpointPLC) result = true;
}
for (const key in store.state.warmers.channels) {
const el = store.state.warmers.channels[key];
if (el.setpointHMI != el.setpointPLC) result = true;
}
return result;
}
@@ -83,6 +83,10 @@ export default class ShowImbutituraInfo extends Vue {
const el = this.payload[key] as Recipe.IValue;
if (el.setpointHMI != el.setpointPLC) result = true;
}
for (const key in store.state.warmers.channels) {
const el = store.state.warmers.channels[key];
if (el.setpointHMI != el.setpointPLC) result = true;
}
return result;
}
@@ -165,6 +165,10 @@ export default class ShowOpzioniInfo extends Vue {
const el = this.payload[key] as Recipe.IValue;
if (el.setpointHMI != el.setpointPLC) result = true;
}
for (const key in store.state.warmers.channels) {
const el = store.state.warmers.channels[key];
if (el.setpointHMI != el.setpointPLC) result = true;
}
return result;
}
@@ -17,11 +17,19 @@ import { debounce } from "@/_base/debounce";
export default class ShowPirometroInfo extends Vue {
recipe: Recipe.IRecipe = this.$store.getters.getCurrent();
show: number = 0;
show: string = 'pyrometer';
@Prop()
deferred: Deferred<boolean>;
@Prop()
value: string;
mounted() {
if (this.value)
this.show = this.value;
}
annulla() {
recipeService.Cancel();
// ModalHelper.HideModal();
@@ -75,13 +83,17 @@ export default class ShowPirometroInfo extends Vue {
const el = this.payload[key] as Recipe.IValue;
if (el.setpointHMI != el.setpointPLC) result = true;
}
for (const key in store.state.warmers.channels) {
const el = store.state.warmers.channels[key];
if (el.setpointHMI != el.setpointPLC) result = true;
}
return result;
}
hasEnabledFields(...fields: string[]) {
let result = false;
for (const field of fields) {
if ((this.recipe[field] as Recipe.IValue).status.enabled) result = true;
if ((this.recipe[field] as Recipe.IValue).status.visible) result = true;
}
return result;
}
@@ -2,15 +2,15 @@
<div class="setup">
<modal type="pirometro-info">
<div class="tab-header" slot="header-buttons">
<button :class="{'active':show==0}" @click="show=0">Pirometro</button>
<button :class="{'active':show=='pyrometer'}" @click="show='pyrometer'">Pirometro</button>
<button
:class="{'active':show==1}"
@click="show=1"
:class="{'active':show=='upperthermoregulator'}"
@click="show='upperthermoregulator'"
v-if="isUpperthermoregulatorEnabled()"
>{{'upperthermoregulator' | localize('Termoregolazione riscaldo superiore')}}</button>
<button
:class="{'active':show==2}"
@click="show=2"
:class="{'active':show=='lowerthermoregulator'}"
@click="show='lowerthermoregulator'"
v-if="isLowerthermoregulatorEnabled()"
>{{'lowerthermoregulator' | localize('Termoregolazione riscaldo inferiore')}}</button>
</div>
@@ -19,9 +19,9 @@
<i class="fa fa-remove"></i>
</button>
</div>
<pirometro v-if="show==0" :recipe="recipe"></pirometro>
<termosuperiore v-if="show==1" :recipe="recipe"></termosuperiore>
<termoinferiore v-if="show==2" :recipe="recipe"></termoinferiore>
<pirometro v-if="show=='pyrometer'" :recipe="recipe"></pirometro>
<termosuperiore v-if="show=='upperthermoregulator'" :recipe="recipe"></termosuperiore>
<termoinferiore v-if="show=='lowerthermoregulator'" :recipe="recipe"></termoinferiore>
<footer>
<button
class="btn"
@@ -4,24 +4,24 @@
<div class="borded_label" id="quota1">
<div v-focus-on:positions_frame_intermediate_position>
<img src="assets/icons/png/salita.png" />
<span>{{recipe.positions_frame_intermediate_position.setpointHMI}}</span>
<span>{{recipe.positions_frame_intermediate_position.valueAct}}</span>
<small>{{recipe.positions_frame_intermediate_position.unitMeasure}}</small>
</div>
<div v-focus-on:positions_frame_intermediate_speed>
<img src="assets/icons/png/bassa.png" />
<span>{{recipe.positions_frame_intermediate_speed.setpointHMI}}</span>
<span>{{recipe.positions_frame_intermediate_speed.valueAct}}</span>
<small>{{recipe.positions_frame_intermediate_speed.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota5">
<div v-focus-on:positions_frame_lower_position>
<img src="assets/icons/png/discesa.png" />
<span>{{recipe.positions_frame_lower_position.setpointHMI}}</span>
<span>{{recipe.positions_frame_lower_position.valueAct}}</span>
<small>{{recipe.positions_frame_lower_position.unitMeasure}}</small>
</div>
<div v-focus-on:positions_frame_lower_speed>
<img src="assets/icons/png/alta.png" />
<span>{{recipe.positions_frame_lower_speed.setpointHMI}}</span>
<span>{{recipe.positions_frame_lower_speed.valueAct}}</span>
<small>{{recipe.positions_frame_lower_speed.unitMeasure}}</small>
</div>
</div>
@@ -4,35 +4,29 @@
<div class="borded_label" id="quota1" v-focus-on:positions_mould_intermediate_position>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.positions_mould_intermediate_position.setpointHMI}}</span>
<span>{{recipe.positions_mould_intermediate_position.valueAct}}</span>
<small>{{recipe.positions_mould_intermediate_position.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota2" v-focus-on>
<div>
<img src="assets/icons/png/quota.png" />
<span>00</span>
<small>mm</small>
</div>
</div>
<div class="borded_label" id="quota3" v-focus-on>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_mould_min_height.setpointHMI}}</span>
<span>{{recipe.general_sizes_mould_min_height.valueAct}}</span>
<small>{{recipe.general_sizes_mould_min_height.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota4" v-focus-on>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_mould_base_height.setpointHMI}}</span>
<span>{{recipe.general_sizes_mould_base_height.valueAct}}</span>
<small>{{recipe.general_sizes_mould_base_height.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota5" v-focus-on>
<div>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_mould_max_height.setpointHMI}}</span>
<span>{{recipe.general_sizes_mould_max_height.valueAct}}</span>
<small>{{recipe.general_sizes_mould_max_height.unitMeasure}}</small>
</div>
</div>
@@ -40,48 +34,48 @@
<div class="borded_label" id="quota6">
<div v-focus-on:positions_mould_upperdeceleration_position>
<img src="assets/icons/png/salita.png" />
<span>{{recipe.positions_mould_upperdeceleration_position.setpointHMI}}</span>
<span>{{recipe.positions_mould_upperdeceleration_position.valueAct}}</span>
<small>{{recipe.positions_mould_upperdeceleration_position.unitMeasure}}</small>
</div>
<div v-focus-on:positions_mould_upperdeceleration_speed>
<img src="assets/icons/png/bassa.png" />
<span>{{recipe.positions_mould_upperdeceleration_speed.setpointHMI}}</span>
<span>{{recipe.positions_mould_upperdeceleration_speed.valueAct}}</span>
<small>{{recipe.positions_mould_upperdeceleration_speed.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota7">
<div v-focus-on:positions_mould_upper_position>
<img src="assets/icons/png/salita.png" />
<span>{{recipe.positions_mould_upper_position.setpointHMI}}</span>
<span>{{recipe.positions_mould_upper_position.valueAct}}</span>
<small>{{recipe.positions_mould_upper_position.unitMeasure}}</small>
</div>
<div v-focus-on:positions_mould_upper_speed>
<img src="assets/icons/png/alta.png" />
<span>{{recipe.positions_mould_upper_speed.setpointHMI}}</span>
<span>{{recipe.positions_mould_upper_speed.valueAct}}</span>
<small>{{recipe.positions_mould_upper_speed.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota8">
<div v-focus-on:positions_mould_lowerdeceleration_position>
<img src="assets/icons/png/discesa.png" />
<span>{{recipe.positions_mould_lowerdeceleration_position.setpointHMI}}</span>
<span>{{recipe.positions_mould_lowerdeceleration_position.valueAct}}</span>
<small>{{recipe.positions_mould_lowerdeceleration_position.unitMeasure}}</small>
</div>
<div v-focus-on:positions_mould_lowerdeceleration_speed>
<img src="assets/icons/png/bassa.png" />
<span>{{recipe.positions_mould_lowerdeceleration_speed.setpointHMI}}</span>
<span>{{recipe.positions_mould_lowerdeceleration_speed.valueAct}}</span>
<small>{{recipe.positions_mould_lowerdeceleration_speed.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota9">
<div v-focus-on:positions_mould_lower_position>
<img src="assets/icons/png/discesa.png" />
<span>{{recipe.positions_mould_lower_position.setpointHMI}}</span>
<span>{{recipe.positions_mould_lower_position.valueAct}}</span>
<small>{{recipe.positions_mould_lower_position.unitMeasure}}</small>
</div>
<div v-focus-on:positions_mould_lower_speed>
<img src="assets/icons/png/alta.png" />
<span>{{recipe.positions_mould_lower_speed.setpointHMI}}</span>
<span>{{recipe.positions_mould_lower_speed.valueAct}}</span>
<small>{{recipe.positions_mould_lower_speed.unitMeasure}}</small>
</div>
</div>
@@ -89,13 +83,9 @@
</template>
<style scoped>
#quota1 {
top: 140px;
top: calc(140px + 260px);
left: 300px;
}
#quota2 {
top: 540px;
left: 100px;
}
#quota3 {
top: 455px;
left: 670px;
@@ -109,19 +99,19 @@
left: 670px;
}
#quota9 {
top: 255px;
top: calc(255px + 260px);
left: 485px;
}
#quota8 {
top: 140px;
top: calc(140px + 260px);
left: 510px;
}
#quota6 {
top: 120px;
top: calc(120px + 260px);
left: 20px;
}
#quota7 {
top: 230px;
top: calc(230px + 260px);
left: 100px;
}
</style>
@@ -4,55 +4,55 @@ e<template>
<div class="borded_label" id="quota3">
<div v-focus-on:positions_upperplate_lower_position>
<img src="assets/icons/png/discesa.png" />
<span>{{recipe.positions_upperplate_lower_position.setpointHMI}}</span>
<span>{{recipe.positions_upperplate_lower_position.valueAct}}</span>
<small>{{recipe.positions_upperplate_lower_position.unitMeasure}}</small>
</div>
<div v-focus-on:positions_upperplate_lower_speed>
<img src="assets/icons/png/alta.png" />
<span>{{recipe.positions_upperplate_lower_speed.setpointHMI}}</span>
<span>{{recipe.positions_upperplate_lower_speed.valueAct}}</span>
<small>{{recipe.positions_upperplate_lower_speed.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota4">
<div v-focus-on:positions_upperplate_lowerdeceleration_position>
<img src="assets/icons/png/discesa.png" />
<span>{{recipe.positions_upperplate_lowerdeceleration_position.setpointHMI}}</span>
<span>{{recipe.positions_upperplate_lowerdeceleration_position.valueAct}}</span>
<small>{{recipe.positions_upperplate_lowerdeceleration_position.unitMeasure}}</small>
</div>
<div v-focus-on:positions_upperplate_lowerdeceleration_speed>
<img src="assets/icons/png/bassa.png" />
<span>{{recipe.positions_upperplate_lowerdeceleration_speed.setpointHMI}}</span>
<span>{{recipe.positions_upperplate_lowerdeceleration_speed.valueAct}}</span>
<small>{{recipe.positions_upperplate_lowerdeceleration_speed.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota1">
<div v-focus-on:positions_upperplate_upper_position>
<img src="assets/icons/png/salita.png" />
<span>{{recipe.positions_upperplate_upper_position.setpointHMI}}</span>
<span>{{recipe.positions_upperplate_upper_position.valueAct}}</span>
<small>{{recipe.positions_upperplate_upper_position.unitMeasure}}</small>
</div>
<div v-focus-on:positions_upperplate_upper_speed>
<img src="assets/icons/png/alta.png" />
<span>{{recipe.positions_upperplate_upper_speed.setpointHMI}}</span>
<span>{{recipe.positions_upperplate_upper_speed.valueAct}}</span>
<small>{{recipe.positions_upperplate_upper_speed.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota2">
<div v-focus-on:positions_upperplate_upperdeceleration_position>
<img src="assets/icons/png/salita.png" />
<span>{{recipe.positions_upperplate_upperdeceleration_position.setpointHMI}}</span>
<span>{{recipe.positions_upperplate_upperdeceleration_position.valueAct}}</span>
<small>{{recipe.positions_upperplate_upperdeceleration_position.unitMeasure}}</small>
</div>
<div v-focus-on:positions_upperplate_upperdeceleration_speed>
<img src="assets/icons/png/bassa.png" />
<span>{{recipe.positions_upperplate_upperdeceleration_speed.setpointHMI}}</span>
<span>{{recipe.positions_upperplate_upperdeceleration_speed.valueAct}}</span>
<small>{{recipe.positions_upperplate_upperdeceleration_speed.unitMeasure}}</small>
</div>
</div>
<div class="borded_label" id="quota5">
<div v-focus-on:general_sizes_upperplate_max_height>
<img src="assets/icons/png/quota.png" />
<span>{{recipe.general_sizes_upperplate_max_height.setpointHMI}}</span>
<span>{{recipe.general_sizes_upperplate_max_height.valueAct}}</span>
<small>{{recipe.general_sizes_upperplate_max_height.unitMeasure}}</small>
</div>
</div>
@@ -25,11 +25,20 @@ import { debounce } from "@/_base/debounce";
export default class ShowQuoteVelocitaInfo extends Vue {
recipe: Recipe.IRecipe = this.$store.getters.getCurrent();
show: number = 0;
show: string = 'mould';
@Prop()
deferred: Deferred<boolean>;
@Prop()
value: string;
mounted() {
if (this.value)
this.show = this.value;
}
annulla() {
recipeService.Cancel();
// ModalHelper.HideModal();
@@ -88,13 +97,17 @@ export default class ShowQuoteVelocitaInfo extends Vue {
const el = this.payload[key] as Recipe.IValue;
if (el.setpointHMI != el.setpointPLC) result = true;
}
for (const key in store.state.warmers.channels) {
const el = store.state.warmers.channels[key];
if (el.setpointHMI != el.setpointPLC) result = true;
}
return result;
}
hasEnabledFields(...fields: string[]) {
let result = false;
for (const field of fields) {
if ((this.recipe[field] as Recipe.IValue).status.enabled) result = true;
if ((this.recipe[field] as Recipe.IValue).status.visible) result = true;
}
return result;
}
@@ -3,18 +3,18 @@
<modal type="quote-velocita-info">
<div class="tab-header" slot="header-buttons">
<button
:class="{'active':show == 0}"
@click="show=0"
:class="{'active':show == 'mould'}"
@click="show='mould'"
v-if="isMouldEnabled()"
>{{'mould' | localize("Stampo")}}</button>
<button
:class="{'active':show == 1}"
@click="show=1"
:class="{'active':show == 'frame'}"
@click="show='frame'"
v-if="isFrameEnabled()"
>{{'frame' | localize("Cornice")}}</button>
<button
:class="{'active':show == 2}"
@click="show=2"
:class="{'active':show == 'upperplate'}"
@click="show='upperplate'"
v-if="isUpperplateEnabled()"
>{{'upperplate' | localize("Controstampo")}}</button>
</div>
@@ -23,9 +23,9 @@
<i class="fa fa-remove"></i>
</button>
</div>
<salita-stampo v-if="show==0" :recipe="recipe"></salita-stampo>
<discesacornice v-if="show==1" :recipe="recipe"></discesacornice>
<controstampo v-if="show==2" :recipe="recipe"></controstampo>
<salita-stampo v-if="show=='mould'" :recipe="recipe"></salita-stampo>
<discesacornice v-if="show=='frame'" :recipe="recipe"></discesacornice>
<controstampo v-if="show=='upperplate'" :recipe="recipe"></controstampo>
<footer>
<button
class="btn"
@@ -32,7 +32,15 @@ export default class Raffreddamento extends Vue {
deferred: Deferred<boolean>;
recipe: Recipe.IRecipe = this.$store.getters.getCurrent();
show: number = 0;
show: string = 'blowing';
@Prop()
value: string;
mounted() {
if (this.value)
this.show = this.value;
}
annulla() {
recipeService.Cancel();
@@ -98,6 +106,10 @@ export default class Raffreddamento extends Vue {
const el = this.payload[key] as Recipe.IValue;
if (el.setpointHMI != el.setpointPLC) result = true;
}
for (const key in store.state.warmers.channels) {
const el = store.state.warmers.channels[key];
if (el.setpointHMI != el.setpointPLC) result = true;
}
return result;
}
@@ -105,7 +117,7 @@ export default class Raffreddamento extends Vue {
hasEnabledFields(...fields: string[]) {
let result = false;
for (const field of fields) {
if ((this.recipe[field] as Recipe.IValue).status.enabled) result = true;
if ((this.recipe[field] as Recipe.IValue).status.visible) result = true;
}
return result;
}
@@ -3,28 +3,28 @@
<modal type="raffreddamento-info">
<div class="tab-header" slot="header-buttons">
<button
:class="{'active':show == 0}"
@click="show=0"
:class="{'active':show == 'blowing'}"
@click="show='blowing'"
v-if="isBlowingEnabled()"
>{{'blowers' | localize("Ventilatori")}}</button>
<button
:class="{'active':show == 1}"
@click="show=1"
:class="{'active':show == 'pyrometer'}"
@click="show='pyrometer'"
v-if="isPyrometerEnabled()"
>{{'pyrometers' | localize("Pirometro")}}</button>
<button
:class="{'active':show == 2}"
@click="show=2"
:class="{'active':show == 'nebulizer'}"
@click="show='nebulizer'"
v-if="isNebulizerEnabled()"
>{{'nebulizers' | localize("Nebulizzatori")}}</button>
<button
:class="{'active':show == 3}"
@click="show=3"
:class="{'active':show == 'telescopic'}"
@click="show='telescopic'"
v-if="isTelescopicEnabled()"
>{{'telescopic' | localize("Telescopi")}}</button>
<button
:class="{'active':show == 4}"
@click="show=4"
:class="{'active':show == 'shutter'}"
@click="show='shutter'"
v-if="isShutterEnabled()"
>{{'shutters' | localize("Otturatori")}}</button>
</div>
@@ -33,11 +33,11 @@
<i class="fa fa-remove"></i>
</button>
</div>
<ventilatori v-if="show==0" :recipe="recipe"></ventilatori>
<pirometro v-if="show==1" :recipe="recipe"></pirometro>
<nebulizzatori v-if="show==2" :recipe="recipe"></nebulizzatori>
<telescopi v-if="show==3" :recipe="recipe"></telescopi>
<otturatori v-if="show==4" :recipe="recipe"></otturatori>
<ventilatori v-if="show=='blowing'" :recipe="recipe"></ventilatori>
<pirometro v-if="show=='pyrometer'" :recipe="recipe"></pirometro>
<nebulizzatori v-if="show=='nebulizer'" :recipe="recipe"></nebulizzatori>
<telescopi v-if="show=='telescopic'" :recipe="recipe"></telescopi>
<otturatori v-if="show=='shutter'" :recipe="recipe"></otturatori>
<footer>
<button
class="btn"
@@ -18,11 +18,19 @@ import { debounce } from "@/_base/debounce";
export default class ShowRiscaldamentoSuperioreInfo extends Vue {
recipe: Recipe.IRecipe = this.$store.getters.getCurrent();
show: number = 0;
show: string = 'upperheaters';
@Prop()
deferred: Deferred<boolean>;
@Prop()
value: string;
mounted() {
if (this.value)
this.show = this.value;
}
annulla(name: string) {
recipeService.Cancel();
// ModalHelper.HideModal();
@@ -72,13 +80,17 @@ export default class ShowRiscaldamentoSuperioreInfo extends Vue {
const el = this.payload[key] as Recipe.IValue;
if (el.setpointHMI != el.setpointPLC) result = true;
}
for (const key in store.state.warmers.channels) {
const el = store.state.warmers.channels[key];
if (el.setpointHMI != el.setpointPLC) result = true;
}
return result;
}
hasEnabledFields(...fields: string[]) {
let result = false;
for (const field of fields) {
if ((this.recipe[field] as Recipe.IValue).status.enabled) result = true;
if ((this.recipe[field] as Recipe.IValue).status.visible) result = true;
}
return result;
}
@@ -3,18 +3,18 @@
<modal type="riscaldi-info">
<div class="tab-header" slot="header-buttons">
<button
:class="{'active':show == 0}"
@click="show = 0"
:class="{'active':show == 'upperheaters'}"
@click="show = 'upperheaters'"
v-if="isUpperheatersEnabled()"
>{{'upperheaters' | localize('Riscaldi superiori')}}</button>
<button
:class="{'active':show == 1}"
@click="show = 1"
:class="{'active':show == 'lowerheaters'}"
@click="show = 'lowerheaters'"
v-if="isLowerheatersEnabled()"
>{{'lowerheaters' | localize('Riscaldi inferiori')}}</button>
<button
:class="{'active':show == 2}"
@click="show = 2"
:class="{'active':show == 'decomsustain'}"
@click="show = 'decomsustain'"
v-if="isDecomsustainEnabled()"
>{{'decomsustain' | localize("Sostentamento/Decompressione")}}</button>
</div>
@@ -23,10 +23,10 @@
<i class="fa fa-remove"></i>
</button>
</div>
<riscaldiinf v-if="show == 1" :recipe="recipe"></riscaldiinf>
<riscaldisup v-if="show == 0" :recipe="recipe"></riscaldisup>
<sostdecomp v-if="show == 2" :recipe="recipe"></sostdecomp>
<footer>
<riscaldiinf v-if="show == 'lowerheaters'" :recipe="recipe"></riscaldiinf>
<riscaldisup v-if="show == 'upperheaters'" :recipe="recipe"></riscaldisup>
<sostdecomp v-if="show == 'decomsustain'" :recipe="recipe"></sostdecomp>
<footer>
<button
class="btn"
@click="annulla()"
@@ -100,13 +100,17 @@ export default class ShowVuotoInfo extends Vue {
const el = this.payload[key] as Recipe.IValue;
if (el.setpointHMI != el.setpointPLC) result = true;
}
for (const key in store.state.warmers.channels) {
const el = store.state.warmers.channels[key];
if (el.setpointHMI != el.setpointPLC) result = true;
}
return result;
}
hasEnabledFields(...fields: string[]) {
let result = false;
for (const field of fields) {
if ((this.recipe[field] as Recipe.IValue).status.enabled) result = true;
if ((this.recipe[field] as Recipe.IValue).status.visible) result = true;
}
return result;
}

Some files were not shown because too many files have changed in this diff Show More