Initial commit - Delphi MES client project

This commit is contained in:
Developer
2026-05-07 20:25:34 +08:00
commit 819b4824f6
466 changed files with 1176403 additions and 0 deletions
+630
View File
@@ -0,0 +1,630 @@
unit uCommonUtils;
interface
uses
SysUtils, Classes, System.JSON, System.Generics.Collections, System.UITypes,
FMX.Forms, FMX.Controls, FMX.StdCtrls;
type
TValidationResult = record
IsValid: Boolean;
ErrorMessage: string;
ErrorField: string;
procedure Clear;
class function Success: TValidationResult; static;
class function Failure(const AErrorField, AErrorMessage: string): TValidationResult; static;
end;
TValidator = class
public
class function IsEmpty(const AValue: string): Boolean; static;
class function IsInteger(const AValue: string): Boolean; static;
class function IsFloat(const AValue: string): Boolean; static;
class function IsDateTime(const AValue: string): Boolean; static;
class function IsEmail(const AValue: string): Boolean; static;
class function IsPhone(const AValue: string): Boolean; static;
class function IsIPAddress(const AValue: string): Boolean; static;
class function MinLength(const AValue: string; AMinLen: Integer): Boolean; static;
class function MaxLength(const AValue: string; AMaxLen: Integer): Boolean; static;
class function InRange(const AValue: string; AMin, AMax: Double): Boolean; static;
class function ValidateBarcode(const ABarcode: string): TValidationResult; static;
class function ValidateLotNo(const ALotNo: string): TValidationResult; static;
class function ValidateMaterialCode(const AMaterialCode: string): TValidationResult; static;
end;
TStringHelperEx = class helper for TStringHelper
public
function IsInteger: Boolean;
function IsFloat: Boolean;
function ToIntegerDef(ADefault: Integer): Integer;
function ToFloatDef(ADefault: Double): Double;
function TrimLeft: string;
function TrimRight: string;
function RemoveWhitespace: string;
function Contains(const ASubStr: string): Boolean;
function StartsWith(const AStr: string): Boolean;
function EndsWith(const AStr: string): Boolean;
function ReplaceAll(const AFrom, ATo: string): string;
end;
TDateTimeHelper = class
public
class function FormatDateTime(const AFormat: string; ADateTime: TDateTime): string; static;
class function ParseDateTime(const AValue: string): TDateTime; static;
class function GetDateOnly(ADateTime: TDateTime): TDate; static;
class function GetTimeOnly(ADateTime: TDateTime): TTime; static;
class function StartOfDay(ADateTime: TDateTime): TDateTime; static;
class function EndOfDay(ADateTime: TDateTime): TDateTime; static;
class function GetAge(ABirthDate: TDateTime): Integer; static;
class function IsToday(ADateTime: TDateTime): Boolean; static;
class function IsSameDay(ADate1, ADate2: TDateTime): Boolean; static;
end;
TFileHelper = class
public
class function ReadTextFile(const AFileName: string; AEncoding: TEncoding = nil): string; static;
class procedure WriteTextFile(const AFileName: string; const AContent: string; AEncoding: TEncoding = nil); static;
class function FileExists(const AFileName: string): Boolean; static;
class function GetFileSize(const AFileName: string): Int64; static;
class function GetFileExtension(const AFileName: string): string; static;
class function GetFileNameWithoutExtension(const AFileName: string): string; static;
class procedure EnsureDirectoryExists(const ADirPath: string); static;
class function GetTempFileName(const AExtension: string = '.tmp'): string; static;
class function GetAppDataPath: string; static;
end;
TJSONHelper = class
public
class function GetString(AJSON: TJSONObject; const AKey: string; const ADefault: string = ''): string; static;
class function GetInteger(AJSON: TJSONObject; const AKey: string; const ADefault: Integer = 0): Integer; static;
class function GetFloat(AJSON: TJSONObject; const AKey: string; const ADefault: Double = 0.0): Double; static;
class function GetBoolean(AJSON: TJSONObject; const AKey: string; const ADefault: Boolean = False): Boolean; static;
class function GetJSONObject(AJSON: TJSONObject; const AKey: string): TJSONObject; static;
class function GetJSONArray(AJSON: TJSONObject; const AKey: string): TJSONArray; static;
class function TryGetString(AJSON: TJSONObject; const AKey: string; out AValue: string): Boolean; static;
class function TryGetInteger(AJSON: TJSONObject; const AKey: string; out AValue: Integer): Boolean; static;
class function ObjectToString(AJSON: TJSONObject): string; static;
class function StringToObject(const AJSONString: string): TJSONObject; static;
end;
TUIHelper = class
public
class procedure ShowMessage(const AMessage: string); static;
class function ShowMessageOKCancel(const AMessage: string): Boolean; static;
class procedure ShowError(const AMessage: string); static;
class procedure ShowInfo(const AMessage: string); static;
class procedure ShowWarning(const AMessage: string); static;
class procedure SetControlEnabled(AControl: TControl; AEnabled: Boolean); static;
class procedure SetControlsEnabled(AControls: array of TControl; AEnabled: Boolean); static;
class procedure UpdateUI(AControl: TControl; AProc: TProc); static;
class function GetScreenScale: Single; static;
end;
implementation
{ TValidationResult }
procedure TValidationResult.Clear;
begin
IsValid := True;
ErrorMessage := '';
ErrorField := '';
end;
class function TValidationResult.Success: TValidationResult;
begin
Result.Clear;
end;
class function TValidationResult.Failure(const AErrorField, AErrorMessage: string): TValidationResult;
begin
Result.IsValid := False;
Result.ErrorField := AErrorField;
Result.ErrorMessage := AErrorMessage;
end;
{ TValidator }
class function TValidator.IsEmpty(const AValue: string): Boolean;
begin
Result := Trim(AValue) = '';
end;
class function TValidator.IsInteger(const AValue: string): Boolean;
var
I: Integer;
begin
Result := TryStrToInt(AValue, I);
end;
class function TValidator.IsFloat(const AValue: string): Boolean;
var
F: Double;
begin
Result := TryStrToFloat(AValue, F);
end;
class function TValidator.IsDateTime(const AValue: string): Boolean;
var
DT: TDateTime;
begin
Result := TryStrToDateTime(AValue, DT);
end;
class function TValidator.IsEmail(const AValue: string): Boolean;
var
I, J: Integer;
begin
Result := False;
if IsEmpty(AValue) then Exit;
I := Pos('@', AValue);
if I = 0 then Exit;
if Pos('.', Copy(AValue, I, Length(AValue))) = 0 then Exit;
J := Length(AValue);
if (I > 1) and (J > I) then
Result := True;
end;
class function TValidator.IsPhone(const AValue: string): Boolean;
var
S: string;
I: Integer;
begin
Result := False;
S := '';
for I := 1 to Length(AValue) do
begin
if AValue[I] in ['0'..'9', '+', '-', '(', ')'] then
S := S + AValue[I];
end;
if Length(S) >= 7 then
Result := True;
end;
class function TValidator.IsIPAddress(const AValue: string): Boolean;
var
Parts: TArray<string>;
I, Val: Integer;
begin
Result := False;
Parts := AValue.Split(['.']);
if Length(Parts) <> 4 then Exit;
for I := 0 to 3 do
begin
if not TryStrToInt(Parts[I], Val) then Exit;
if (Val < 0) or (Val > 255) then Exit;
end;
Result := True;
end;
class function TValidator.MinLength(const AValue: string; AMinLen: Integer): Boolean;
begin
Result := Length(AValue) >= AMinLen;
end;
class function TValidator.MaxLength(const AValue: string; AMaxLen: Integer): Boolean;
begin
Result := Length(AValue) <= AMaxLen;
end;
class function TValidator.InRange(const AValue: string; AMin, AMax: Double): Boolean;
var
F: Double;
begin
Result := False;
if not TryStrToFloat(AValue, F) then Exit;
Result := (F >= AMin) and (F <= AMax);
end;
class function TValidator.ValidateBarcode(const ABarcode: string): TValidationResult;
begin
Result := TValidationResult.Success;
if IsEmpty(ABarcode) then
Exit(TValidationResult.Failure('Barcode', 'Barcode cannot be empty'));
if Length(ABarcode) < 8 then
Exit(TValidationResult.Failure('Barcode', 'Barcode must be at least 8 characters'));
if Length(ABarcode) > 50 then
Exit(TValidationResult.Failure('Barcode', 'Barcode must not exceed 50 characters'));
end;
class function TValidator.ValidateLotNo(const ALotNo: string): TValidationResult;
begin
Result := TValidationResult.Success;
if IsEmpty(ALotNo) then
Exit(TValidationResult.Failure('LotNo', 'Lot number cannot be empty'));
if Length(ALotNo) < 6 then
Exit(TValidationResult.Failure('LotNo', 'Lot number must be at least 6 characters'));
end;
class function TValidator.ValidateMaterialCode(const AMaterialCode: string): TValidationResult;
begin
Result := TValidationResult.Success;
if IsEmpty(AMaterialCode) then
Exit(TValidationResult.Failure('MaterialCode', 'Material code cannot be empty'));
if Length(AMaterialCode) < 3 then
Exit(TValidationResult.Failure('MaterialCode', 'Material code must be at least 3 characters'));
end;
{ TStringHelperEx }
function TStringHelperEx.IsInteger: Boolean;
begin
Result := TValidator.IsInteger(Self.ToString);
end;
function TStringHelperEx.IsFloat: Boolean;
begin
Result := TValidator.IsFloat(Self.ToString);
end;
function TStringHelperEx.ToIntegerDef(ADefault: Integer): Integer;
begin
if not TryStrToInt(Self.ToString, Result) then
Result := ADefault;
end;
function TStringHelperEx.ToFloatDef(ADefault: Double): Double;
begin
if not TryStrToFloat(Self.ToString, Result) then
Result := ADefault;
end;
function TStringHelperEx.TrimLeft: string;
begin
Result := System.StrUtils.TrimLeft(Self.ToString);
end;
function TStringHelperEx.TrimRight: string;
begin
Result := System.StrUtils.TrimRight(Self.ToString);
end;
function TStringHelperEx.RemoveWhitespace: string;
var
I: Integer;
begin
Result := '';
for I := 1 to Length(Self.ToString) do
begin
if not CharInSet(Self.ToString[I], [' ', #9, #10, #13]) then
Result := Result + Self.ToString[I];
end;
end;
function TStringHelperEx.Contains(const ASubStr: string): Boolean;
begin
Result := Pos(ASubStr, Self.ToString) > 0;
end;
function TStringHelperEx.StartsWith(const AStr: string): Boolean;
begin
Result := Copy(Self.ToString, 1, Length(AStr)) = AStr;
end;
function TStringHelperEx.EndsWith(const AStr: string): Boolean;
begin
Result := Copy(Self.ToString, Length(Self.ToString) - Length(AStr) + 1, Length(AStr)) = AStr;
end;
function TStringHelperEx.ReplaceAll(const AFrom, ATo: string): string;
begin
Result := System.StrUtils.ReplaceStr(Self.ToString, AFrom, ATo);
end;
{ TDateTimeHelper }
class function TDateTimeHelper.FormatDateTime(const AFormat: string; ADateTime: TDateTime): string;
begin
Result := System.SysUtils.FormatDateTime(AFormat, ADateTime);
end;
class function TDateTimeHelper.ParseDateTime(const AValue: string): TDateTime;
begin
if not TryStrToDateTime(AValue, Result) then
Result := 0;
end;
class function TDateTimeHelper.GetDateOnly(ADateTime: TDateTime): TDate;
begin
Result := Trunc(ADateTime);
end;
class function TDateTimeHelper.GetTimeOnly(ADateTime: TDateTime): TTime;
begin
Result := ADateTime - Trunc(ADateTime);
end;
class function TDateTimeHelper.StartOfDay(ADateTime: TDateTime): TDateTime;
begin
Result := Trunc(ADateTime);
end;
class function TDateTimeHelper.EndOfDay(ADateTime: TDateTime): TDateTime;
begin
Result := Trunc(ADateTime) + 1 - OneSecond;
end;
class function TDateTimeHelper.GetAge(ABirthDate: TDateTime): Integer;
begin
Result := YearOf(Now) - YearOf(ABirthDate);
if (MonthOf(Now) < MonthOf(ABirthDate)) or
((MonthOf(Now) = MonthOf(ABirthDate)) and (DayOf(Now) < DayOf(ABirthDate))) then
Dec(Result);
end;
class function TDateTimeHelper.IsToday(ADateTime: TDateTime): Boolean;
begin
Result := IsSameDay(ADateTime, Now);
end;
class function TDateTimeHelper.IsSameDay(ADate1, ADate2: TDateTime): Boolean;
begin
Result := (Trunc(ADate1) = Trunc(ADate2));
end;
{ TFileHelper }
class function TFileHelper.ReadTextFile(const AFileName: string; AEncoding: TEncoding = nil): string;
begin
Result := '';
if not FileExists(AFileName) then Exit;
if AEncoding = nil then
AEncoding := TEncoding.UTF8;
Result := TFile.ReadAllText(AFileName, AEncoding);
end;
class procedure TFileHelper.WriteTextFile(const AFileName: string; const AContent: string; AEncoding: TEncoding = nil);
begin
if AEncoding = nil then
AEncoding := TEncoding.UTF8;
EnsureDirectoryExists(ExtractFilePath(AFileName));
TFile.WriteAllText(AFileName, AContent, AEncoding);
end;
class function TFileHelper.FileExists(const AFileName: string): Boolean;
begin
Result := System.SysUtils.FileExists(AFileName);
end;
class function TFileHelper.GetFileSize(const AFileName: string): Int64;
var
F: TFileStream;
begin
Result := 0;
if not FileExists(AFileName) then Exit;
F := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
try
Result := F.Size;
finally
F.Free;
end;
end;
class function TFileHelper.GetFileExtension(const AFileName: string): string;
begin
Result := System.SysUtils.ExtractFileExt(AFileName);
end;
class function TFileHelper.GetFileNameWithoutExtension(const AFileName: string): string;
begin
Result := System.SysUtils.ChangeFileExt(System.SysUtils.ExtractFileName(AFileName), '');
end;
class procedure TFileHelper.EnsureDirectoryExists(const ADirPath: string);
begin
if not DirectoryExists(ADirPath) then
ForceDirectories(ADirPath);
end;
class function TFileHelper.GetTempFileName(const AExtension: string = '.tmp'): string;
var
TempPath: string;
begin
TempPath := System.SysUtils.GetTempPath;
Result := TempPath + ChangeFileExt(System.SysUtils.ExtractFileName(ParamStr(0)), '') + '_' + IntToStr(GetCurrentThreadID) + AExtension;
end;
class function TFileHelper.GetAppDataPath: string;
begin
Result := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + 'Data\';
EnsureDirectoryExists(Result);
end;
{ TJSONHelper }
class function TJSONHelper.GetString(AJSON: TJSONObject; const AKey: string; const ADefault: string = ''): string;
var
Pair: TJSONPair;
begin
Result := ADefault;
Pair := AJSON.GetValue(AKey);
if Pair <> nil then
Result := Pair.JsonValue.Value;
end;
class function TJSONHelper.GetInteger(AJSON: TJSONObject; const AKey: string; const ADefault: Integer = 0): Integer;
var
Pair: TJSONPair;
begin
Result := ADefault;
Pair := AJSON.GetValue(AKey);
if Pair <> nil then
begin
if Pair.JsonValue is TJSONNumber then
Result := TJSONNumber(Pair.JsonValue).AsInt
else
TryStrToInt(Pair.JsonValue.Value, Result);
end;
end;
class function TJSONHelper.GetFloat(AJSON: TJSONObject; const AKey: string; const ADefault: Double = 0.0): Double;
var
Pair: TJSONPair;
begin
Result := ADefault;
Pair := AJSON.GetValue(AKey);
if Pair <> nil then
begin
if Pair.JsonValue is TJSONNumber then
Result := TJSONNumber(Pair.JsonValue).AsDouble
else
TryStrToFloat(Pair.JsonValue.Value, Result);
end;
end;
class function TJSONHelper.GetBoolean(AJSON: TJSONObject; const AKey: string; const ADefault: Boolean = False): Boolean;
var
Pair: TJSONPair;
begin
Result := ADefault;
Pair := AJSON.GetValue(AKey);
if Pair <> nil then
begin
if Pair.JsonValue is TJSONTrue then
Result := True
else if Pair.JsonValue is TJSONFalse then
Result := False;
end;
end;
class function TJSONHelper.GetJSONObject(AJSON: TJSONObject; const AKey: string): TJSONObject;
var
Pair: TJSONPair;
begin
Result := nil;
Pair := AJSON.GetValue(AKey);
if Pair <> nil then
if Pair.JsonValue is TJSONObject then
Result := TJSONObject(Pair.JsonValue);
end;
class function TJSONHelper.GetJSONArray(AJSON: TJSONObject; const AKey: string): TJSONArray;
var
Pair: TJSONPair;
begin
Result := nil;
Pair := AJSON.GetValue(AKey);
if Pair <> nil then
if Pair.JsonValue is TJSONArray then
Result := TJSONArray(Pair.JsonValue);
end;
class function TJSONHelper.TryGetString(AJSON: TJSONObject; const AKey: string; out AValue: string): Boolean;
var
Pair: TJSONPair;
begin
Result := False;
AValue := '';
Pair := AJSON.GetValue(AKey);
if Pair <> nil then
begin
AValue := Pair.JsonValue.Value;
Result := True;
end;
end;
class function TJSONHelper.TryGetInteger(AJSON: TJSONObject; const AKey: string; out AValue: Integer): Boolean;
var
Pair: TJSONPair;
begin
Result := False;
AValue := 0;
Pair := AJSON.GetValue(AKey);
if Pair <> nil then
begin
if Pair.JsonValue is TJSONNumber then
begin
AValue := TJSONNumber(Pair.JsonValue).AsInt;
Result := True;
end
else if TryStrToInt(Pair.JsonValue.Value, AValue) then
Result := True;
end;
end;
class function TJSONHelper.ObjectToString(AJSON: TJSONObject): string;
begin
if AJSON <> nil then
Result := AJSON.ToJSON
else
Result := '';
end;
class function TJSONHelper.StringToObject(const AJSONString: string): TJSONObject;
begin
Result := nil;
if AJSONString = '' then Exit;
try
Result := TJSONObject.ParseJSONValue(AJSONString) as TJSONObject;
except
Result := nil;
end;
end;
{ TUIHelper }
class procedure TUIHelper.ShowMessage(const AMessage: string);
begin
if not Application.Active then Exit;
Application.MessageBox(AMessage, 'Information', MB_OK + MB_ICONINFORMATION);
end;
class function TUIHelper.ShowMessageOKCancel(const AMessage: string): Boolean;
begin
Result := False;
if not Application.Active then Exit;
Result := Application.MessageBox(AMessage, 'Confirm', MB_OKCANCEL + MB_ICONQUESTION) = ID_OK;
end;
class procedure TUIHelper.ShowError(const AMessage: string);
begin
if not Application.Active then Exit;
Application.MessageBox(AMessage, 'Error', MB_OK + MB_ICONERROR);
end;
class procedure TUIHelper.ShowInfo(const AMessage: string);
begin
ShowMessage(AMessage);
end;
class procedure TUIHelper.ShowWarning(const AMessage: string);
begin
if not Application.Active then Exit;
Application.MessageBox(AMessage, 'Warning', MB_OK + MB_ICONWARNING);
end;
class procedure TUIHelper.SetControlEnabled(AControl: TControl; AEnabled: Boolean);
begin
if AControl = nil then Exit;
AControl.Enabled := AEnabled;
end;
class procedure TUIHelper.SetControlsEnabled(AControls: array of TControl; AEnabled: Boolean);
var
Ctrl: TControl;
begin
for Ctrl in AControls do
SetControlEnabled(Ctrl, AEnabled);
end;
class procedure TUIHelper.UpdateUI(AControl: TControl; AProc: TProc);
begin
if AControl = nil then Exit;
AControl.BeginUpdate;
try
AProc;
finally
AControl.EndUpdate;
end;
end;
class function TUIHelper.GetScreenScale: Single;
begin
if Application.MainForm <> nil then
Result := Application.MainForm.CurrentPPI / 96.0
else
Result := 1.0;
end;
end.