unit uDM; { ================================================ 数据模块单元 - uDM.pas ================================================ 【模块说明】 本单元是应用程序的核心数据模块(TDataModule),负责: - 管理主从表结构的数据操作 - 提供内存表(MemTable)的CRUD功能 - 处理业务数据的持久化和加载 - 管理工单和批次记录 【数据结构】 - FDMemMain: 主表,存储工单批次等核心业务数据 - FDMemDetail: 从表,存储详细生产记录 - FDMemTable1: 配置表,存储系统配置和键值对 【主要功能】 - 主从表数据插入、删除、更新操作 - 内存表数据加载和保存 - 配置信息的读写管理 - 后台数据同步线程 【使用注意】 - 使用FireDAC内存表支持离线操作 - 数据变更后需要调用SaveMain/SaveDetail保存 - 线程安全:TDbSoapThread用于后台数据同步 【版本信息】 - 创建时间: 2024年 - 最后修改: 2026年4月 - 版本: 1.0 ================================================ } interface uses System.SysUtils, System.Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Param, FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf,System.Variants, FireDAC.DApt.Intf, FireDAC.Stan.StorageBin, FireDAC.Stan.StorageJSON, Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client,FMX.TabControl,FMX.Grid,System.JSON, System.ImageList, FMX.ImgList,uKsoap,Winapi.ActiveX,uSafelog,FMX.Dialogs, Vcl.ImgList, Vcl.Controls, uExceptionHandler; type TDbSoapThread = class(TThread) private protected procedure Execute; override; public constructor Create; end; TDM = class(TDataModule) FDMemTable1: TFDMemTable; FDMemTable1ID: TIntegerField; FDMemTable1TabName: TStringField; FDMemTable1KeyName: TStringField; FDMemTable1KeyDesc: TStringField; FDMemTable1KeyValue: TStringField; FDStanStorageJSONLink1: TFDStanStorageJSONLink; ImageList1: TImageList; FDStanStorageBinLink1: TFDStanStorageBinLink; FDMemMain: TFDMemTable; FDMemDetail: TFDMemTable; procedure DataModuleCreate(Sender: TObject); private function CreateMainTable():boolean; function CreateDetailTable():boolean; public MainUI,DataOpline,Operate:Integer; procedure MemTableLoadTab(TabName:string;GridFrame:TStringGrid); procedure MemTableSaveTab(GridFrame:TStringGrid); procedure MemTableReadTabList(var Strings: TStrings); function MemTableReadKeyValue(TabName,KeyName:string):string; procedure MemTableWriteKeyValue(TabName,KeyName,Value:string); procedure MemTableWriteKey(TabName,KeyName:string); procedure ClearBlankTab(); function TabNameExists(TabName:string):boolean; //主从表 function InsertDetail(vId:Integer;DetailRecord:TDetailRecord):boolean; function InsertMain(var vId:Integer;LotNoRecord:TLotNoRecord;IsOnlyMain:boolean=false):boolean; function InsertQtyTime(vID,vP_ID,vP_ACT_QTY,vP_LINE_SPEED,vP_BK1,vP_BK2,vP_BK3:string):boolean; function UpdateMainId(vID:Integer;vP_ID:string;Inserted:boolean):boolean; function DeleteDetailById(vID:Integer):boolean; function DeleteMainById(vID:Integer):boolean; function SaveMain():boolean; function SaveDetail():boolean;//从表 function LoadMain():boolean; function LoadDetail():boolean; //从表 procedure Tim_Timer(sText: String); // function SaveMainToRecord(var LotNoRecord:TLotNoRecord); // function SaveDetailToRecord(var DetailRecord:TDetailRecord); //InsertLotEntity(null, FACTORY_CODE, mWorkNum, mLotNum, PROCESS, PRODUCT_LINE, LINE_NUM, LOT_TYPE, "Y", ID, false); end; var DM: TDM; implementation Uses System.StrUtils; {%CLASSGROUP 'FMX.Controls.TControl'} {$R *.dfm} function TDM.CreateMainTable():boolean; begin FDMemMain.Close; with FDMemMain.FieldDefs do begin Clear; Add('ID', ftAutoInc); Add('P_ORG_CODE',ftString,30,false); Add('P_NUM',ftString,30,false); Add('P_LOT',ftString,30,false); Add('P_PC',ftString,30,false); Add('P_LINE',ftString,30,false); Add('P_LINE_NUM',ftString,30,false); Add('P_LOT_TYPE',ftString,30,false); Add('P_BKfile',ftString,30,false); Add('P_Buffer',ftString,30,false); Add('P_DIE_NAME',ftString,30,false); Add('P_Enable',ftString,30,false); Add('P_MESH',ftString,30,false); Add('P_COUNTERPOINT_MODE',ftString,30,false); Add('P_SHORT_CIRCUIT',ftString,30,false); Add('P_CREATION_DATE',ftString,30,false); Add('P_TROLLEY_NUM',ftString,30,false); Add('P_TROLLEY_FLAG',ftString,30,false); Add('P_COPPER_MODEL',ftString,30,false); Add('P_COMP_PROGRAM',ftString,30,false); Add('P_COMP_AREA',ftString,30,false); Add('P_PLATE_WIDTH',ftString,30,false); Add('P_PLATE_HEIGHT',ftString,30,false); Add('P_JET_FLOW',ftString,30,false); Add('P_SIDE',ftString,30,false); Add('P_DRY_FILM_TYPE',ftString,30,false); Add('P_NEGATIVE',ftString,30,false); Add('P_ID',ftString,30,false); Add('P_LINE_SPEED',ftSingle,0,false); Add('P_ELE_CUR_DENSITY',ftSingle,0,false); Add('P_ELE_AREA1',ftSingle,0,false); Add('P_ELE_AREA2',ftSingle,0,false); Add('P_COM_TEMPERATURE',ftSingle,0,false); Add('P_PRODUCT_PRESSURE',ftSingle,0,false); Add('P_PREHEATING_SEC',ftSingle,0,false); Add('P_COMPRESS_SEC',ftSingle,0,false); Add('P_STAMPING_DEPTH',ftSingle,0,false); Add('P_DIE_USE_NUM',ftSingle,0,false); Add('P_NUM_PER_ARR',ftSingle,0,false); Add('P_UPPER_PRESSURE',ftSingle,0,false); Add('P_DOWN_PRESSURE',ftSingle,0,false); Add('P_SLICKER_ANGLE',ftSingle,0,false); Add('P_INK_KNIFE_ANGLE',ftSingle,0,false); Add('P_SLICKER_SPEED',ftSingle,0,false); Add('P_INK_KNIFE_SPEED',ftSingle,0,false); Add('P_NET_SPACING',ftSingle,0,false); Add('P_EXPOSURE_TIME',ftSingle,0,false); Add('P_SLAB_THICKNESS',ftSingle,0,false); Add('P_JE_SETUP',ftSingle,0,false); Add('P_EXPOSURE_ENERGY',ftSingle,0,false); Add('P_DEVELOP_PRESSURE',ftSingle,0,false); Add('P_ETCH_FACTOR',ftSingle,0,false); Add('P_RESOLUTION',ftSingle,0,false); Add('P_SLICKER_PRESSURE',ftSingle,0,false); Add('P_INK_KNIFE_PRESSURE',ftSingle,0,false); Add('P_OFF_NET',ftSingle,0,false); Add('P_SLICKER_DEPTH',ftSingle,0,false); Add('P_INK_RETURN_KNIFE_DEPTH',ftSingle,0,false); Add('Inserted',ftBoolean,0,false); Add('IsOnlyMain',ftBoolean,0,false); end; FDMemMain.CreateDataSet(); end; function TDM.CreateDetailTable():boolean; begin FDMemDetail.Close; with FDMemDetail.FieldDefs do begin Clear; Add('ID', ftAutoInc); Add('ParentID',ftInteger,0,false); Add('P_ORG_CODE',ftString,30,false); Add('P_BC',ftString,30,false); Add('P_LOT',ftString,30,false); Add('P_PC',ftString,30,false); Add('P_LINE',ftString,30,false); Add('P_LINE_NUM',ftString,30,false); Add('P_LOT_TYPE',ftString,30,false); Add('P_ID',ftString,30,false); Add('P_TROLLEY_NUM',ftString,30,false); Add('P_COPPER_MODEL',ftString,30,false); Add('P_BUFFER_TYPE',ftString,30,false); Add('P_CREATION_DATE',ftString,30,false); Add('iNum',ftInteger,0,false); //当前记数 Add('Style',ftInteger,0,false); // 1=明细, 2=最后提交更新 Add('P_BK1',ftString,30,false); Add('P_BK2',ftString,30,false); Add('P_BK3',ftString,30,false); Add('P_ACT_QTY',ftString,30,false); Add('P_END_TIME',ftString,30,false); Add('P_LINE_SPEED',ftString,30,false); end; FDMemDetail.CreateDataSet(); end; function TDM.SaveMain():boolean; begin FDMemMain.CachedUpdates; FDMemMain.CommitUpdates; FDMemMain.SaveToFile(ExtractFilePath(Paramstr(0))+'tmpdb/main.dat',sfBinary); end; function TDM.SaveDetail():boolean;//从表 begin FDMemDetail.CachedUpdates; FDMemDetail.CommitUpdates; FDMemDetail.SaveToFile(ExtractFilePath(Paramstr(0))+'tmpdb/Detail.dat',sfBinary); end; function TDM.LoadMain():boolean; var sFileName, FLogFileDir:string; begin FLogFileDir := ExtractFilePath(Paramstr(0))+'tmpdb'; if not DirectoryExists(FLogFileDir) then if not ForceDirectories(FLogFileDir) then //创建目录 begin RaiseDataException('tmpdb路径错误,数据类对象不能被创建', 1001); end; sFileName:=ExtractFilePath(Paramstr(0))+'tmpdb/main.dat'; if FileExists(sFileName) then begin FDMemMain.LoadFromFile(sFileName,sfBinary); WorkLog.MessageInfo('主表记录数:%d',[FDMemMain.RecordCount]); end; end; function TDM.LoadDetail():boolean; //从表 var sFileName:string; begin sFileName:=ExtractFilePath(Paramstr(0))+'tmpdb/Detail.dat'; if FileExists(sFileName) then begin FDMemDetail.LoadFromFile(ExtractFilePath(Paramstr(0))+'tmpdb/Detail.dat',sfBinary); WorkLog.MessageInfo('从表记录数:%d',[FDMemDetail.RecordCount]); end; end; function TDM.TabNameExists(TabName:string):boolean; begin Result:=FDMemTable1.Locate('TabName',TabName); end; procedure TDM.DataModuleCreate(Sender: TObject); begin if FileExists(ExtractFilePath(Paramstr(0))+'system.json') then FDMemTable1.LoadFromFile(ExtractFilePath(Paramstr(0))+'system.json'); FDMemTable1.LogChanges := False; FDMemTable1.Active:=true; FDMemTable1.DisableControls; with FDMemMain do begin LogChanges := False; CachedUpdates:=false; fetchoptions.RecsMax:=300000; resourceoptions.SilentMode:=true; UpdateOptions.LockMode:=lmNone; UpdateOptions.LockPoint:=lpDeferred; UpdateOptions.FetchGeneratorsPoint:=gpImmediate; DisableControls; CreateMainTable(); Active:=true; end; with FDMemDetail do begin LogChanges := False; CachedUpdates:=false; fetchoptions.RecsMax:=300000; resourceoptions.SilentMode:=true; UpdateOptions.LockMode:=lmNone; UpdateOptions.LockPoint:=lpDeferred; UpdateOptions.FetchGeneratorsPoint:=gpImmediate; DisableControls; CreateDetailTable(); Active:=true; end; end; function TDM.DeleteDetailById(vID:Integer):boolean; begin System.MonitorEnter(FDMemDetail); try with FDMemDetail do //标记已插入 begin if Locate('ID',vID) then begin delete; SaveDetail; end; end; finally System.MonitorExit(FDMemDetail); end; end; function TDM.DeleteMainById(vID:Integer):boolean; begin System.MonitorEnter(FDMemMain); try with FDMemMain do //标记已插入 begin if Locate('ID',vID) then begin delete; SaveMain; end; end; finally System.MonitorExit(FDMemMain); end; end; procedure TDM.MemTableLoadTab(TabName:string;GridFrame:TStringGrid); var i:integer; begin with FDMemTable1 do begin First; GridFrame.BeginUpdate; i:=0; while not Eof do begin if FieldByName('TabName').AsString=TabName then begin GridFrame.Cells[0,i]:=FieldByName('Id').AsString; GridFrame.Cells[1,i]:=FieldByName('KeyName').AsString; GridFrame.Cells[2,i]:=FieldByName('KeyDesc').AsString; GridFrame.Cells[3,i]:=FieldByName('KeyValue').AsString; inc(i); end; Next; end; GridFrame.EndUpdate; end; end; procedure TDM.ClearBlankTab(); //当9个键值都为空时,删除掉整个TAB面的数据 var TmpTabName:TStrings; i:integer; begin with FDMemTable1 do begin TmpTabName:=TStringlist.Create; MemTableReadTabList(TmpTabName); for i := TmpTabName.Count-1 downto 0 do //去掉有数据的Tab begin First; while not Eof do begin if FieldByName('TabName').AsString=TmpTabName.Strings[i] then begin if (FieldByName('KeyName').AsString<>'') or (FieldByName('KeyDesc').AsString<>'') or (FieldByName('KeyValue').AsString<>'') then //有数据 begin TmpTabName.Delete(i); break; end; end; Next; end; end; //删除无数据的Tab for i := TmpTabName.Count-1 downto 0 do //去掉有数据的Tab begin First; while not Eof do begin if FieldByName('TabName').AsString=TmpTabName.Strings[i] then begin delete; end; Next; end; end; end; end; procedure TDM.MemTableSaveTab(GridFrame:TStringGrid); var i:integer; begin for i := 0 to GridFrame.RowCount-1 do begin with FDMemTable1 do begin if trim(GridFrame.Cells[0,i])<>'' then if Locate('id',GridFrame.Cells[0,i]) then begin Edit; FieldByName('KeyName').AsString:=Trim(GridFrame.Cells[1,i]); FieldByName('KeyDesc').AsString:=Trim(GridFrame.Cells[2,i]); FieldByName('KeyValue').AsString:=Trim(GridFrame.Cells[3,i]).Replace(',',','); Post; //if (FieldByName('KeyName').AsString='') and (FieldByName('KeyDesc').AsString='') //and (FieldByName('KeyValue').AsString='') then //delete; end; end; end; ClearBlankTab; FDMemTable1.MergeChangeLog; FDMemTable1.ApplyUpdates(0); end; procedure TDM.MemTableWriteKey(TabName,KeyName:string); begin with FDMemTable1 do begin Append; FieldByName('TabName').AsString:=TabName; FieldByName('KeyName').AsString:=KeyName; Post; end; end; function TDM.MemTableReadKeyValue(TabName,KeyName:string):string; begin Result:=''; if (TabName<>'') and (KeyName<>'') then begin if FDMemTable1.Locate('TabName;KeyName',vararrayof([TabName,KeyName]),[]) then Result:=FDMemTable1.FieldByName('KeyValue').AsString; end; end; procedure TDM.MemTableWriteKeyValue(TabName,KeyName,Value:string); begin if (TabName<>'') and (KeyName<>'') and (Value<>'') then begin if FDMemTable1.Locate('TabName;KeyName',vararrayof([TabName,KeyName]),[]) then begin FDMemTable1.Edit; FDMemTable1.FieldByName('KeyValue').AsString:= Value; FDMemTable1.Post; fdmemtable1.SaveToFile(ExtractFilePath(Paramstr(0))+'system.json'); WorkLog.MessageInfo(Value+',数据保存成功'); end; end; end; procedure TDM.MemTableReadTabList(var Strings: TStrings); begin FDMemTable1.First; Strings.Clear; while not FDMemTable1.Eof do begin if Strings.IndexOf(FDMemTable1.FieldByName('TabName').AsString)<0 then Strings.Add(FDMemTable1.FieldByName('TabName').AsString); FDMemTable1.Next; end; end; procedure JsonToDataSet(AJson: string; ADataset: TDataSet); var jDataSet: TJSONArray; jRecord: TJSONObject; i, j: Integer; begin if (AJson = '') or (ADataset = nil) or (not ADataset.Active) then Exit; jDataSet := TJSONObject.Create.ParseJSONValue(AJson, True) as TJSONArray; for i :=0 to jDataSet.Size -1 do begin ADataset.Append; jRecord := jDataSet.Get(i) as TJSONObject; for j :=0 to ADataset.FieldCount -1 do ADataset.Fields[j].Text := jRecord.GetValue(ADataset.Fields[j].FieldName).ToString; ADataset.Post; end; end; function DataSetToJson(ADataset: TDataSet): string; var LRecord: string; LField: TField; i: integer; begin Result := ''; if (not ADataset.Active) or (ADataset.IsEmpty) then Exit; Result := '['; ADataset.First; while not ADataset.Eof do begin for i :=0 to ADataset.FieldCount -1 do begin LField := ADataset.Fields[i]; if LRecord = '' then LRecord := '{"' + LField.FieldName + '":"' + LField.Text + '"' else LRecord := LRecord + ',"' + LField.FieldName + '":"' + LField.Text + '"'; if i = ADataset.FieldCount -1 then begin LRecord := LRecord + '}'; if Result = '[' then Result := Result + LRecord else Result := Result + ',' + LRecord; LRecord := ''; end; end; ADataset.Next; end; Result := Result + ']'; end; function TDM.InsertQtyTime(vID,vP_ID,vP_ACT_QTY,vP_LINE_SPEED,vP_BK1,vP_BK2,vP_BK3:string):boolean; begin System.MonitorEnter(FDMemDetail); try WITH FDMemDetail DO BEGIN Append; FieldbyName('P_ID').AsString:=vP_ID; FieldbyName('P_LINE_SPEED').AsString:=vP_LINE_SPEED; FieldbyName('P_BK1').AsString:=vP_BK1; FieldbyName('P_BK2').AsString:=vP_BK2; FieldbyName('P_BK3').AsString:=vP_BK3; FieldbyName('P_ACT_QTY').AsString:=vP_ACT_QTY; FieldbyName('P_END_TIME').AsString:=FormatDateTime('yyyymmdd hh:mm:ss',Now); FieldbyName('Style').AsInteger:=2; FieldByName('ParentId').AsString:=vID; Post; END; finally SaveDetail(); System.MonitorExit(FDMemDetail); end; end; function TDM.InsertDetail(vId:Integer;DetailRecord:TDetailRecord):boolean; // begin System.MonitorEnter(FDMemDetail); try WITH FDMemDetail DO BEGIN Append; FieldbyName('ParentID').AsInteger:=vId; FieldbyName('P_ORG_CODE').AsString:=DetailRecord.P_ORG_CODE; FieldbyName('P_BC').AsString:=DetailRecord.P_BC; FieldbyName('P_LOT').AsString:=DetailRecord.P_LOT; FieldbyName('P_PC').AsString:=DetailRecord.P_PC; FieldbyName('P_LINE').AsString:=DetailRecord.P_LINE; FieldbyName('P_LINE_NUM').AsString:=DetailRecord.P_LINE_NUM; FieldbyName('P_LOT_TYPE').AsString:=DetailRecord.P_LOT_TYPE; FieldbyName('P_ID').AsString:=DetailRecord.P_ID; FieldbyName('P_TROLLEY_NUM').AsString:=DetailRecord.P_TROLLEY_NUM; FieldbyName('P_COPPER_MODEL').AsString:=DetailRecord.P_COPPER_MODEL; FieldbyName('P_BUFFER_TYPE').AsString:=DetailRecord.P_BUFFER_TYPE; FieldbyName('P_CREATION_DATE').AsString:=DetailRecord.P_CREATION_DATE; FieldbyName('Style').Index:=1; Post; END; finally SaveDetail(); System.MonitorExit(FDMemDetail); end; END; function TDM.InsertMain(var vId:Integer;LotNoRecord:TLotNoRecord;IsOnlyMain:boolean=false):boolean; BEGIN Result:=false; System.MonitorEnter(FDMemMain); try WITH FDMemMain DO BEGIN Append; FieldByName('P_ORG_CODE').AsString:=LotNoRecord.P_ORG_CODE; FieldByName('P_NUM').AsString:=LotNoRecord.P_NUM; FieldByName('P_LOT').AsString:=LotNoRecord.P_LOT; FieldByName('P_PC').AsString:=LotNoRecord.P_PC; FieldByName('P_LINE').AsString:=LotNoRecord.P_LINE; FieldByName('P_LINE_NUM').AsString:=LotNoRecord.P_LINE_NUM; FieldByName('P_LOT_TYPE').AsString:=LotNoRecord.P_LOT_TYPE; FieldByName('P_BKfile').AsString:=LotNoRecord.P_BKfile; FieldByName('P_Buffer').AsString:=LotNoRecord.P_Buffer; FieldByName('P_DIE_NAME').AsString:=LotNoRecord.P_DIE_NAME; FieldByName('P_Enable').AsString:=LotNoRecord.P_Enable; FieldByName('P_MESH').AsString:=LotNoRecord.P_MESH; FieldByName('P_COUNTERPOINT_MODE').AsString:=LotNoRecord.P_COUNTERPOINT_MODE; FieldByName('P_SHORT_CIRCUIT').AsString:=LotNoRecord.P_SHORT_CIRCUIT; FieldByName('P_CREATION_DATE').AsString:=LotNoRecord.P_CREATION_DATE; FieldByName('P_TROLLEY_NUM').AsString:=LotNoRecord.P_TROLLEY_NUM; FieldByName('P_TROLLEY_FLAG').AsString:=LotNoRecord.P_TROLLEY_FLAG; FieldByName('P_COPPER_MODEL').AsString:=LotNoRecord.P_COPPER_MODEL; FieldByName('P_COMP_PROGRAM').AsString:=LotNoRecord.P_COMP_PROGRAM; FieldByName('P_COMP_AREA').AsString:=LotNoRecord.P_COMP_AREA; FieldByName('P_PLATE_WIDTH').AsString:=LotNoRecord.P_PLATE_WIDTH; FieldByName('P_PLATE_HEIGHT').AsString:=LotNoRecord.P_PLATE_HEIGHT; FieldByName('P_JET_FLOW').AsString:=LotNoRecord.P_JET_FLOW; FieldByName('P_SIDE').AsString:=LotNoRecord.P_SIDE; FieldByName('P_DRY_FILM_TYPE').AsString:=LotNoRecord.P_DRY_FILM_TYPE; FieldByName('P_NEGATIVE').AsString:=LotNoRecord.P_NEGATIVE; FieldByName('P_ID').AsString:=LotNoRecord.P_ID.ToString; FieldByName('P_LINE_SPEED').AsSingle:=LotNoRecord.P_LINE_SPEED; FieldByName('P_ELE_CUR_DENSITY').AsSingle:=LotNoRecord.P_ELE_CUR_DENSITY; FieldByName('P_ELE_AREA1').AsSingle:=LotNoRecord.P_ELE_AREA1; FieldByName('P_ELE_AREA2').AsSingle:=LotNoRecord.P_ELE_AREA2; FieldByName('P_COM_TEMPERATURE').AsSingle:=LotNoRecord.P_COM_TEMPERATURE; FieldByName('P_PRODUCT_PRESSURE').AsSingle:=LotNoRecord.P_PRODUCT_PRESSURE; FieldByName('P_PREHEATING_SEC').AsSingle:=LotNoRecord.P_PREHEATING_SEC; FieldByName('P_COMPRESS_SEC').AsSingle:=LotNoRecord.P_COMPRESS_SEC; FieldByName('P_STAMPING_DEPTH').AsSingle:=LotNoRecord.P_STAMPING_DEPTH; FieldByName('P_DIE_USE_NUM').AsSingle:=LotNoRecord.P_DIE_USE_NUM; FieldByName('P_NUM_PER_ARR').AsSingle:=LotNoRecord.P_NUM_PER_ARR; FieldByName('P_UPPER_PRESSURE').AsSingle:=LotNoRecord.P_UPPER_PRESSURE; FieldByName('P_DOWN_PRESSURE').AsSingle:=LotNoRecord.P_DOWN_PRESSURE; FieldByName('P_SLICKER_ANGLE').AsSingle:=LotNoRecord.P_SLICKER_ANGLE; FieldByName('P_INK_KNIFE_ANGLE').AsSingle:=LotNoRecord.P_INK_KNIFE_ANGLE; FieldByName('P_SLICKER_SPEED').AsSingle:=LotNoRecord.P_SLICKER_SPEED; FieldByName('P_INK_KNIFE_SPEED').AsSingle:=LotNoRecord.P_INK_KNIFE_SPEED; FieldByName('P_NET_SPACING').AsSingle:=LotNoRecord.P_NET_SPACING; FieldByName('P_EXPOSURE_TIME').AsSingle:=LotNoRecord.P_EXPOSURE_TIME; FieldByName('P_SLAB_THICKNESS').AsSingle:=LotNoRecord.P_SLAB_THICKNESS; FieldByName('P_JE_SETUP').AsSingle:=LotNoRecord.P_JE_SETUP; FieldByName('P_EXPOSURE_ENERGY').AsSingle:=LotNoRecord.P_EXPOSURE_ENERGY; FieldByName('P_DEVELOP_PRESSURE').AsSingle:=LotNoRecord.P_DEVELOP_PRESSURE; FieldByName('P_ETCH_FACTOR').AsSingle:=LotNoRecord.P_ETCH_FACTOR; FieldByName('P_RESOLUTION').AsSingle:=LotNoRecord.P_RESOLUTION; FieldByName('P_SLICKER_PRESSURE').AsSingle:=LotNoRecord.P_SLICKER_PRESSURE; FieldByName('P_INK_KNIFE_PRESSURE').AsSingle:=LotNoRecord.P_INK_KNIFE_PRESSURE; FieldByName('P_OFF_NET').AsSingle:=LotNoRecord.P_OFF_NET; FieldByName('P_SLICKER_DEPTH').AsSingle:=LotNoRecord.P_SLICKER_DEPTH; FieldByName('P_INK_RETURN_KNIFE_DEPTH').AsSingle:=LotNoRecord.P_INK_RETURN_KNIFE_DEPTH; FieldByName('Inserted').asboolean:=false; FieldByName('IsOnlyMain').asboolean:=IsOnlyMain; Post; vId:=FieldByName('ID').AsInteger; Result:=true; END; finally SaveMain(); System.MonitorExit(FDMemMain); end; END; function TDM.UpdateMainId(vID:Integer;vP_ID:string;Inserted:boolean):boolean; BEGIN System.MonitorEnter(FDMemMain); try with FDMemMain do //标记已插入 begin if FDMemMain.Locate('ID',vID) then begin Edit; FieldByName('Inserted').asboolean:=Inserted; FieldByName('P_ID').AsString:=vP_ID; Post; SaveMain; end; end; finally System.MonitorExit(FDMemMain); end; END; //////////////////////////////////////////////////////////////////////////////////// constructor TDbSoapThread.Create(); begin inherited Create(True); FreeOnTerminate := True; end; procedure TDbSoapThread.Execute; //提交数据 VAR vP_ID:Double; sError:string; vId:Integer; bHaveNoSucced:boolean; LotNoRecord:TLotNoRecord; DetailRecord:TDetailRecord; LotNoBuf,DetailBuf:TFDMemTable; procedure CopyDataSet(AOptions:TFDCopyDataSetOptions); begin System.MonitorEnter(dm.FDMemMain); try LotNoBuf.CopyDataSet(dm.FDMemMain,AOptions); finally System.MonitorExit(dm.FDMemMain); end; System.MonitorEnter(dm.FDMemDetail); try DetailBuf.CopyDataSet(dm.FDMemDetail,AOptions); finally System.MonitorExit(dm.FDMemDetail); end; end; procedure SaveMainToRecord(var vLotNoRecord:TLotNoRecord); begin with LotNoBuf do begin LotNoRecord.P_ORG_CODE:=FieldByName('P_ORG_CODE').AsString; LotNoRecord.P_NUM:=FieldByName('P_NUM').AsString; LotNoRecord.P_LOT:=FieldByName('P_LOT').AsString; LotNoRecord.P_PC:=FieldByName('P_PC').AsString; LotNoRecord.P_LINE:=FieldByName('P_LINE').AsString; LotNoRecord.P_LINE_NUM:=FieldByName('P_LINE_NUM').AsString; LotNoRecord.P_LOT_TYPE:=FieldByName('P_LOT_TYPE').AsString; LotNoRecord.P_BKfile:=FieldByName('P_BKfile').AsString; LotNoRecord.P_Buffer:=FieldByName('P_Buffer').AsString; LotNoRecord.P_DIE_NAME:=FieldByName('P_DIE_NAME').AsString; LotNoRecord.P_Enable:=FieldByName('P_Enable').AsString; LotNoRecord.P_MESH:=FieldByName('P_MESH').AsString; LotNoRecord.P_COUNTERPOINT_MODE:=FieldByName('P_COUNTERPOINT_MODE').AsString; LotNoRecord.P_SHORT_CIRCUIT:=FieldByName('P_SHORT_CIRCUIT').AsString; LotNoRecord.P_CREATION_DATE:=FieldByName('P_CREATION_DATE').AsString; LotNoRecord.P_TROLLEY_NUM:=FieldByName('P_TROLLEY_NUM').AsString; LotNoRecord.P_TROLLEY_FLAG:=FieldByName('P_TROLLEY_FLAG').AsString; LotNoRecord.P_COPPER_MODEL:=FieldByName('P_COPPER_MODEL').AsString; LotNoRecord.P_COMP_PROGRAM:=FieldByName('P_COMP_PROGRAM').AsString; LotNoRecord.P_COMP_AREA:=FieldByName('P_COMP_AREA').AsString; LotNoRecord.P_PLATE_WIDTH:=FieldByName('P_PLATE_WIDTH').AsString; LotNoRecord.P_PLATE_HEIGHT:=FieldByName('P_PLATE_HEIGHT').AsString; LotNoRecord.P_JET_FLOW:=FieldByName('P_JET_FLOW').AsString; LotNoRecord.P_SIDE:=FieldByName('P_SIDE').AsString; LotNoRecord.P_DRY_FILM_TYPE:=FieldByName('P_DRY_FILM_TYPE').AsString; LotNoRecord.P_NEGATIVE:=FieldByName('P_NEGATIVE').AsString; LotNoRecord.P_ID:=FieldByName('P_ID').AsFloat; LotNoRecord.P_LINE_SPEED:=FieldByName('P_LINE_SPEED').AsSingle; LotNoRecord.P_ELE_CUR_DENSITY:=FieldByName('P_ELE_CUR_DENSITY').AsSingle; LotNoRecord.P_ELE_AREA1:=FieldByName('P_ELE_AREA1').AsSingle; LotNoRecord.P_ELE_AREA2:=FieldByName('P_ELE_AREA2').AsSingle; LotNoRecord.P_COM_TEMPERATURE:=FieldByName('P_COM_TEMPERATURE').AsSingle; LotNoRecord.P_PRODUCT_PRESSURE:=FieldByName('P_PRODUCT_PRESSURE').AsSingle; LotNoRecord.P_PREHEATING_SEC:=FieldByName('P_PREHEATING_SEC').AsSingle; LotNoRecord.P_COMPRESS_SEC:=FieldByName('P_COMPRESS_SEC').AsSingle; LotNoRecord.P_STAMPING_DEPTH:=FieldByName('P_STAMPING_DEPTH').AsSingle; LotNoRecord.P_DIE_USE_NUM:=FieldByName('P_DIE_USE_NUM').AsSingle; LotNoRecord.P_NUM_PER_ARR:=FieldByName('P_NUM_PER_ARR').AsSingle; LotNoRecord.P_UPPER_PRESSURE:=FieldByName('P_UPPER_PRESSURE').AsSingle; LotNoRecord.P_DOWN_PRESSURE:=FieldByName('P_DOWN_PRESSURE').AsSingle; LotNoRecord.P_SLICKER_ANGLE:=FieldByName('P_SLICKER_ANGLE').AsSingle; LotNoRecord.P_INK_KNIFE_ANGLE:=FieldByName('P_INK_KNIFE_ANGLE').AsSingle; LotNoRecord.P_SLICKER_SPEED:=FieldByName('P_SLICKER_SPEED').AsSingle; LotNoRecord.P_INK_KNIFE_SPEED:=FieldByName('P_INK_KNIFE_SPEED').AsSingle; LotNoRecord.P_NET_SPACING:=FieldByName('P_NET_SPACING').AsSingle; LotNoRecord.P_EXPOSURE_TIME:=FieldByName('P_EXPOSURE_TIME').AsSingle; LotNoRecord.P_SLAB_THICKNESS:=FieldByName('P_SLAB_THICKNESS').AsSingle; LotNoRecord.P_JE_SETUP:=FieldByName('P_JE_SETUP').AsSingle; LotNoRecord.P_EXPOSURE_ENERGY:=FieldByName('P_EXPOSURE_ENERGY').AsSingle; LotNoRecord.P_DEVELOP_PRESSURE:=FieldByName('P_DEVELOP_PRESSURE').AsSingle; LotNoRecord.P_ETCH_FACTOR:=FieldByName('P_ETCH_FACTOR').AsSingle; LotNoRecord.P_RESOLUTION:=FieldByName('P_RESOLUTION').AsSingle; LotNoRecord.P_SLICKER_PRESSURE:=FieldByName('P_SLICKER_PRESSURE').AsSingle; LotNoRecord.P_INK_KNIFE_PRESSURE:=FieldByName('P_INK_KNIFE_PRESSURE').AsSingle; LotNoRecord.P_OFF_NET:=FieldByName('P_OFF_NET').AsSingle; LotNoRecord.P_SLICKER_DEPTH:=FieldByName('P_SLICKER_DEPTH').AsSingle; LotNoRecord.P_INK_RETURN_KNIFE_DEPTH:=FieldByName('P_INK_RETURN_KNIFE_DEPTH').AsSingle; end; end; procedure SaveDetailToRecord(var vDetailRecord:TDetailRecord); begin with DetailBuf do begin DetailRecord.P_ORG_CODE:=FieldbyName('P_ORG_CODE').AsString; DetailRecord.P_BC:=FieldbyName('P_BC').AsString; DetailRecord.P_LOT:=FieldbyName('P_LOT').AsString; DetailRecord.P_PC:=FieldbyName('P_PC').AsString; DetailRecord.P_LINE:=FieldbyName('P_LINE').AsString; DetailRecord.P_LINE_NUM:=FieldbyName('P_LINE_NUM').AsString; DetailRecord.P_LOT_TYPE:=FieldbyName('P_LOT_TYPE').AsString; DetailRecord.P_ID:=FieldbyName('P_ID').AsString; DetailRecord.P_TROLLEY_NUM:=FieldbyName('P_TROLLEY_NUM').AsString; DetailRecord.P_COPPER_MODEL:=FieldbyName('P_COPPER_MODEL').AsString; DetailRecord.P_BUFFER_TYPE:=FieldbyName('P_BUFFER_TYPE').AsString; DetailRecord.P_CREATION_DATE:=FieldbyName('P_CREATION_DATE').AsString; end; end; begin CoInitialize(nil); LotNoBuf:=TFDMemTable.Create(nil); DetailBuf:=TFDMemTable.Create(nil); try //dm.LoadMain; //dm.LoadDetail; CopyDataSet([coStructure,coRestart, coAppend]); while not self.Terminated do begin Sleep(200); if (LotNoBuf.RecordCount=0) and (DetailBuf.RecordCount=0) then begin Sleep(1000); CopyDataSet([coRestart, coAppend]); continue; end; if ((LotNoBuf.RecordCount=0) and (DetailBuf.RecordCount>0)) then //处理只有从表数据 begin DBApiLog.MessageInfo('存在明细表数据没有提交,请处理'); //找到明细数据,并提交 DetailBuf.First; bHaveNoSucced:=false; while not DetailBuf.Eof do begin SaveDetailToRecord(DetailRecord); DetailRecord.P_ID:=DetailBuf.FieldByName('ParentID').AsInteger.ToString; if Ksoap.Insert_cc_wip_lot_bc_history(DetailRecord,sError) then begin dm.DeleteDetailById(DetailBuf.FieldByName('ID').AsInteger); end else begin //提交不成功 if sError='連接數據庫服務器失败' then begin bHaveNoSucced:=true; DBApiLog.MessageInfo(sError); end else dm.DeleteDetailById(DetailBuf.FieldByName('ID').AsInteger); end; SLEEP(200); DetailBuf.Next; end; continue; end; try LotNoBuf.First; while not LotNoBuf.Eof do //提交主表 begin if (LotNoBuf.FieldByName('P_ID').AsString='0') or (LotNoBuf.FieldByName('P_ID').AsString='') then //取ID begin vP_ID:=Ksoap.cf_traceability_seq_f(LotNoBuf.FieldByName('P_ORG_CODE').AsString,sError); //inc(vP_ID);//////////////////////////////// if vP_ID=0 then //取不到ID begin Sleep(10000); LotNoBuf.Next; continue; end; LotNoBuf.Edit; LotNoBuf.FieldByName('P_ID').AsString:=vP_ID.ToString; vId:=LotNoBuf.FieldByName('ID').AsInteger; LotNoBuf.Post; SaveMainToRecord(LotNoRecord); LotNoRecord.P_ID:=vP_ID; dm.UpdateMainId(vId,vP_ID.ToString,false); //更新主表ID end else //已有ID的,并且未插入的 begin vId:=LotNoBuf.FieldByName('ID').AsInteger; vP_ID:=LotNoBuf.FieldByName('P_ID').AsFloat; if not LotNoBuf.FieldByName('Inserted').asboolean then //未提交 begin SaveMainToRecord(LotNoRecord); LotNoRecord.P_ID:=vP_ID; end else LotNoRecord.P_ORG_CODE:='-1'; end; //提交主表 if LotNoRecord.P_ORG_CODE<>'-1' then //提交 if Ksoap.Insert_CM_WIP_PROCESS_LINE_HISTORY_NEW(LotNoRecord,sError) then //提交主表成功 begin if LotNoBuf.FieldByName('IsOnlyMain').asboolean then //只有主表 dm.DeleteMainById(vId) else dm.UpdateMainId(vId,vP_ID.ToString,True); //更新主表ID end else //主表提交未成功 begin Sleep(1000); LotNoBuf.Next; continue; end; //找到明细数据,并提交 DetailBuf.First; bHaveNoSucced:=false; while not DetailBuf.Eof do begin if DetailBuf.FieldByName('ParentID').AsInteger=vId then //提交从表数据 begin if (DetailBuf.FieldByName('Style').AsInteger=2) and (not bHaveNoSucced) then //最终提交的数据 begin with DetailBuf do if Ksoap.Update_qty_time_p(vP_ID.ToString,FieldByName('P_ACT_QTY').AsString, FieldByName('P_END_TIME').AsString,FieldByName('P_LINE_SPEED').AsString,FieldByName('P_BK1').AsString, FieldByName('P_BK2').AsString,FieldByName('P_BK3').AsString,sError) then begin dm.DeleteDetailById(DetailBuf.FieldByName('ID').AsInteger); //提交成功,删除该记录 dm.DeleteMainById(vId); end; end else begin SaveDetailToRecord(DetailRecord); DetailRecord.P_ID:=vP_ID.ToString; if Ksoap.Insert_cc_wip_lot_bc_history(DetailRecord,sError) then begin dm.DeleteDetailById(DetailBuf.FieldByName('ID').AsInteger); end else begin //提交不成功 if sError='連接數據庫服務器失败' then bHaveNoSucced:=true else dm.DeleteDetailById(DetailBuf.FieldByName('ID').AsInteger); end; end; SLEEP(400); end; DetailBuf.Next; end; LotNoBuf.Next; Sleep(200); end; LotNoBuf.EmptyDataSet; DetailBuf.EmptyDataSet; except workLog.Error('后台线程提交主从数据出错'); Sleep(20000); end; end; finally CoUninitialize; DetailBuf.Free; LotNoBuf.Free; end; end; procedure TDM.Tim_Timer(sText: String); var sPath:string; begin //判断整点,就上传日志 if RightStr(sText,5)=':00:00' then //整点 begin sPath:=TRIM(dm.MemTableReadKeyValue('主要参数','LogBakDir')); if sPath<>'' then CopyLogFile(sPath); end; end; end.