Jelajahi Sumber

TASK #5578
在定额库中增加机械台班动力燃料的动态明细表MachineDetail,可自由新增动力燃料,“工料机汇总”界面的机械台班表格动态显示动力了燃料列。也兼容老式的固定动力燃料数据。

JimiZhang 1 bulan lalu
induk
melakukan
48053131b0

+ 38 - 2
Common/ScConsts.pas

@@ -316,13 +316,37 @@ const
   SNDianCode            = '电';
   // 水
   SNShuiCode            = '水';
-  // 
+  // 木柴
   SNMCCode              = '木柴';
+  // 煤气
+  SNMeiQCode            = '煤气';
   // 液化气
   SNYHQCode             = '液化气';
   // 天然气
   SNTRQCode             = '天然气';
 
+  // 字段标题对应
+  // 重油
+  SZYFieldTitle              = '重油=ZY';
+  // 汽油
+  SQYFieldTitle              = '汽油=QY';
+  // 柴油
+  SCYFieldTitle              = '柴油=CY';
+  // 煤
+  SMeiFieldTitle             = '煤=Mei';
+  // 电
+  SDianFieldTitle            = '电=Dian';
+  // 水
+  SShuiFieldTitle            = '水=Shui';
+  // 木柴
+  SMCFieldTitle              = '木柴=MC';
+  // 煤气
+  SMeiQFieldTitle            = '煤气=MeiQ';
+  // 液化气
+  SYHQFieldTitle             = '液化气=YHQ';
+  // 天然气
+  STRQFieldTitle             = '天然气=TRQ';
+
   // 各种沥青
   LQ1Code = '3001001';
   LQ2Code = '3001002';
@@ -390,8 +414,12 @@ const
 
   //MachineRelaGLs: array [0..9] of string =
   //  (SRGCode, SZYCode, SQYCode, SCYCode, SMeiCode, SDianCode, SShuiCode, SMCCode, SYHQCode, STRQCode);
+  // 全部台班明细
   MachineRelaGLKeys: array [0..10] of string =
     (SRGKeys, SZYKeys, SQYKeys, SCYKeys, SMeiKeys, SDianKeys, SShuiKeys, SMCKeys, SMeiQKeys, SYHQKeys, STRQKeys);
+  // 部颁动力燃料明细
+  MachineStdDLRLKeys: array [0..6] of string =
+    (SZYKeys, SQYKeys, SCYKeys, SMeiKeys, SDianKeys, SShuiKeys, SMCKeys);
 
   // 定额库类型
   // 预算定额库
@@ -955,6 +983,7 @@ resourcestring
   SBBFee               = 'BBFee';
   SKBFee               = 'KBFee';
   SDLRL                = 'DLRL';
+  SDLRLDetail          = 'DLRLDetail';
   SZJ                  = 'ZJ';
   SDXL                 = 'DXL';
   SJCXL                = 'JCXL';
@@ -972,6 +1001,7 @@ resourcestring
   SYLCC                = 'YLCC';
   SDian                = 'Dian';
   SRGType              = 'RGType';
+  SFuel                = 'Fuel';
 
   SProvidePlace        = 'ProvidePlace';
   SOrgPrice            = 'OrgPrice';
@@ -991,6 +1021,8 @@ resourcestring
   SOwnerID  = 'OwnerID';
   SOwnerCode  = 'OwnerCode';
   SOwnerName  = 'OwnerName';
+  SOwnerSpecs  = 'OwnerSpecs';
+  SOwnerUnit  = 'OwnerUnit';
   SOwnerUID  = 'OwnerUID';
   SLocations  = 'Locations';
   SConveyance  = 'Conveyance';
@@ -1372,6 +1404,10 @@ const
   pcn_Show = -2;
   pcn_Last = -1;
 
+  // 动力燃料字段
+  MachineFuelFields: array [0..9] of string =
+    (SZY, SQY, SCY, SMei, SDian, SShui, SMC, SMeiQ, SYHQ, STRQ);
+  
 function BillItemTypeToText(ABillItemType: Integer): string;
 
 // 替代编译指令的变量
@@ -1581,7 +1617,7 @@ begin
       {$ENDIF}
     {$ENDIF}
 
-    
+
     // 下面这些指令具有特殊性,从上面复杂的嵌套中提取出来,简化代码。这里只是临时处理,最好重新组织 CSL.2019.05.28
     {$IFDEF _ScOnLine}
     SDispVerName := '网络学习版';

+ 1 - 1
Common/ScFileArchiverConsts.pas

@@ -80,7 +80,7 @@ const
   ConstRationLibFileVersion = '10.0.1.5';
 
   ConstFeeRateFileVersion = '10.1.3.3';
-  ConstUnitPriceFileVersion = '10.1.4.1005';
+  ConstUnitPriceFileVersion = '10.1.4.1006';
   ConstBillsFairyFileVersion = '1.0.0.1';
   ConstReportsTemplateFileVersion = '1.0.0.1';
   ConstCommonDataFileVersion = '1.0.0.1';

+ 2 - 0
Common/ScMessage.pas

@@ -34,6 +34,8 @@ const
   SCM_CloseAction             = SM_BASE - 21;      // 关闭程序动作(wParam: 0 关闭 1 不关闭)
   SCM_FreeRationLibs          = SM_BASE - 22;      // 项目定额库管理对象释放
 
+  SCM_AddRationLib            = SM_BASE - 23;      // 新增定额库(WParam: 定额库ID)
+
   {TSMBillsItemUintChange = packed record
     Msg: Cardinal;
     Unused: Integer;

+ 39 - 2
Common/ScTablesUnit.pas

@@ -43,7 +43,7 @@ const
 {-----------------------------  项目文件数据库定义  ---------------------------}
   // 表 MachinePrice 定义
   SMachinePrice = 'MachinePrice';
-  tdMachinePrice: array [0..26] of TScFieldDef = (
+  tdMachinePrice: array [0..27] of TScFieldDef = (
     (FieldName: 'ID'; FieldType: ftInteger; Size: 0; Precision: 0; NotNull: True; PrimaryKey: True; ForceUpdate: False),
     (FieldName: 'Code'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
     (FieldName: 'Name'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
@@ -70,7 +70,26 @@ const
     (FieldName: 'TRQ'; FieldType: ftCurrency; Size: 4; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
     (FieldName: 'YLCC'; FieldType: ftCurrency; Size: 4; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
     (FieldName: 'RGType'; FieldType: ftInteger; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
-    (FieldName: 'Visible'; FieldType: ftBoolean; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False)
+    (FieldName: 'Visible'; FieldType: ftBoolean; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'LibID'; FieldType: ftInteger; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False)
+  );
+
+  // 表 MachineDetail 定义
+  SMachineDetail = 'MachineDetail';
+  tdMachineDetail: array [0..12] of TScFieldDef = (
+    (FieldName: 'ID'; FieldType: ftInteger; Size: 0; Precision: 0; NotNull: True; PrimaryKey: True; ForceUpdate: False),
+    (FieldName: 'OwnerID'; FieldType: ftInteger; Size: 0; Precision: 0; NotNull: True; PrimaryKey: True; ForceUpdate: False),
+    (FieldName: 'OwnerCode'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'OwnerName'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'OwnerSpecs'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'OwnerUnit'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Code'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Name'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Specs'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Unit'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'BasePrice'; FieldType: ftCurrency; Size: 4; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'BudgetPrice'; FieldType: ftCurrency; Size: 4; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Quantity'; FieldType: ftDouble; Size: 0; Precision: 0; NotNull: True; PrimaryKey: False; ForceUpdate: False)
   );
 
   // 表 MachinePrice 定义
@@ -1476,6 +1495,24 @@ const
     (FieldName: 'RGType'; FieldType: ftInteger; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False)
   );
 
+  // 表 MachineDetail 定义
+  SUMachineDetail = 'MachineDetail';
+  tdUMachineDetail: array [0..12] of TScFieldDef = (
+    (FieldName: 'ID'; FieldType: ftInteger; Size: 0; Precision: 0; NotNull: True; PrimaryKey: True; ForceUpdate: False),
+    (FieldName: 'OwnerID'; FieldType: ftInteger; Size: 0; Precision: 0; NotNull: True; PrimaryKey: True; ForceUpdate: False),
+    (FieldName: 'OwnerCode'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'OwnerName'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'OwnerSpecs'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'OwnerUnit'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Code'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Name'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Specs'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Unit'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'BasePrice'; FieldType: ftCurrency; Size: 4; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'BudgetPrice'; FieldType: ftCurrency; Size: 4; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Quantity'; FieldType: ftDouble; Size: 0; Precision: 0; NotNull: True; PrimaryKey: False; ForceUpdate: False)
+  );
+
   // 表 MaterialPrice 定义
   SUMaterialPrice = 'MaterialPrice';
 

+ 0 - 16
Common/ScUtils.pas

@@ -262,9 +262,6 @@ type
   function GLJTextToType(ATypeText: string): Integer;
   function GLJCalculateTypeToText(ACalculateType: Integer): string;
   function GLJTextToCalculateType(ACalculateTypeText: string): Integer;
-  // 是否机械相关工料
-  function IsMachineRelaGL(AKey: string): Boolean;
-
   // 复制相同字段的DataSet,字段顺序可不同;返回记录数,错误返回-1
   function CopyDataSet(Source, Target: TDataSet): Integer;
 var
@@ -3615,19 +3612,6 @@ begin
     Result := SGLJ_C_StableMix;
 end;
 
-function IsMachineRelaGL(AKey: string): Boolean;
-var
-  I: Integer;
-begin
-  Result := False;
-  for I := Low(MachineRelaGLKeys) to High(MachineRelaGLKeys) do
-    if AKey = MachineRelaGLKeys[I] then
-    begin
-      Result := True;
-      Break;
-    end;
-end;
-
 { TScTipForm }
 
 constructor TScTipForm.Create(AOwner: TComponent);

+ 8 - 3
Components/SmartDataSet/Source/sdGridDBA.pas

@@ -863,8 +863,13 @@ begin
 end;
 
 function TsdCustomGridDBA.Column(AFieldName: string): TsdGridColumn;
+var
+  iIndex: Integer;
 begin
-  Result := Columns.Items[ColumnIndex(AFieldName)];
+  iIndex := ColumnIndex(AFieldName);
+  Result := nil;
+  if iIndex >= 0 then
+    Result := Columns.Items[iIndex];
 end;
 
 function TsdCustomGridDBA.VisibleCol(AFieldName: string): Integer;
@@ -1211,9 +1216,9 @@ begin
         (Assigned(Col.LookUpField) and (Col.LookUpField.DataType in [ftFloat, ftCurrency, ftBCD, ftFMTBCD]))) then
       AKey := '.';
 
-    if (Col.Field <> nil) then
+    if (Col <> nil) and (Col.Field <> nil) then
       Accept := Col.Field.IsValidChar(AKey)
-    else if (Col.LookUpField <> nil) then
+    else if (Col <> nil) and (Col.LookUpField <> nil) then
       Accept := Col.LookUpField.IsValidChar(AKey)
     else
       Accept := True;

+ 2 - 1
Components/SmartDataSet/Source/sdLogicalExprs.pas

@@ -485,7 +485,8 @@ begin
     begin
       if bIsQuote then
       begin
-        if CompareStr(strText[I - 1], '''') <> 0 then
+        // 2026-06-23 不知道为什么要加上这样一个判断。但是空值就是'',这个判断会导致空值后的空格不被清除,先屏蔽
+        //if CompareStr(strText[I - 1], '''') <> 0 then
           bIsQuote := False;
       end
       else

+ 2 - 2
DPRs/ZY/SmartCost.dof

@@ -115,7 +115,7 @@ AutoIncBuild=1
 MajorVer=10
 MinorVer=3
 Release=0
-Build=1339
+Build=1340
 Debug=0
 PreRelease=0
 Special=0
@@ -126,7 +126,7 @@ CodePage=936
 [Version Info Keys]
 CompanyName=珠海纵横创新软件有限公司
 FileDescription=SmartCost 2025专业版
-FileVersion=10.3.0.1339
+FileVersion=10.3.0.1340
 InternalName=SmartCost
 LegalCopyright=版权所有(C) 珠海纵横创新软件有限公司 2003-2024。保留所有权利。
 LegalTrademarks=SmartCost

TEMPAT SAMPAH
DPRs/ZY/SmartCost.res


+ 2 - 2
DPRs/ZY/SmartCost_GuangDong.dof

@@ -115,7 +115,7 @@ AutoIncBuild=1
 MajorVer=10
 MinorVer=3
 Release=0
-Build=1328
+Build=1338
 Debug=0
 PreRelease=0
 Special=0
@@ -126,7 +126,7 @@ CodePage=936
 [Version Info Keys]
 CompanyName=珠海纵横软件有限公司
 FileDescription=SmartCost 广东专业版
-FileVersion=10.3.0.1328
+FileVersion=10.3.0.1338
 InternalName=SmartCost
 LegalCopyright=版权所有(C) 珠海纵横创新软件有限公司 2003-2024。保留所有权利。
 LegalTrademarks=SmartCost

TEMPAT SAMPAH
DPRs/ZY/SmartCost_GuangDong.res


+ 1 - 1
Debug/CheckProjectDataFrm.pas

@@ -193,7 +193,7 @@ begin
   // 材料计算定额工料机
   Result := Result or TScProject(FProject).ProjectGLJ.MaterialData.GLJUsed(iID);
   // 机械台班工料机
-  Result := Result or IsMachineRelaGL(ProjectGLJRec.Code.AsString);
+  Result := Result or TScProject(FProject).ProjectGLJ.MachineData.IsMachineRelaGL(ProjectGLJRec.Code.AsString);
 end;
 
 procedure TCheckProjectDataForm.sdvProjectGLJFilterRecord(

+ 106 - 3
MainModule/Model/ScMachine.dfm

@@ -4,8 +4,8 @@ object MachineData: TMachineData
   OnDestroy = DataModuleDestroy
   Left = 359
   Top = 177
-  Height = 272
-  Width = 278
+  Height = 318
+  Width = 703
   object sapMachinePrice: TsdADOProvider
     TableName = 'MachinePrice'
     Left = 48
@@ -99,7 +99,10 @@ object MachineData: TMachineData
       4E616D650809507265636973696F6E02000453697A6502000001044E616D6506
       0756697369626C65094669656C644E616D65060756697369626C650844617461
       547970650205084461746153697A6502010549734B6579080F4E65656450726F
-      636573734E616D650809507265636973696F6E02000453697A6502000000}
+      636573734E616D650809507265636973696F6E02000453697A6502000001044E
+      616D6506054C69624944094669656C644E616D6506054C696249440844617461
+      547970650203084461746153697A6502040549734B6579080F4E65656450726F
+      636573734E616D650909507265636973696F6E02000453697A6502000000}
   end
   object sapMachineLabours: TsdADOProvider
     TableName = 'MachineLabours'
@@ -236,4 +239,104 @@ object MachineData: TMachineData
     Left = 144
     Top = 160
   end
+  object sapMachineDetail: TsdADOProvider
+    TableName = 'MachineDetail'
+    Left = 256
+    Top = 24
+  end
+  object sdsMachineDetail: TsdDataSet
+    Active = False
+    Filtered = False
+    Provider = sapMachineDetail
+    UseSavePoint = False
+    OnGetRecordClass = sdsMachineDetailGetRecordClass
+    Left = 256
+    Top = 88
+    FieldListData = {
+      0101044E616D6506024944094669656C644E616D650602494408446174615479
+      70650203084461746153697A6502040549734B6579080F4E65656450726F6365
+      73734E616D650909507265636973696F6E02000453697A6502000001044E616D
+      650604436F6465094669656C644E616D650604436F6465084461746154797065
+      0218084461746153697A6503FF000549734B6579080F4E65656450726F636573
+      734E616D650909507265636973696F6E02000453697A6502000001044E616D65
+      06044E616D65094669656C644E616D6506044E616D6508446174615479706502
+      18084461746153697A6503FF000549734B6579080F4E65656450726F63657373
+      4E616D650909507265636973696F6E02000453697A6502000001044E616D6506
+      055370656373094669656C644E616D6506055370656373084461746154797065
+      0218084461746153697A6503FF000549734B6579080F4E65656450726F636573
+      734E616D650909507265636973696F6E02000453697A6502000001044E616D65
+      0604556E6974094669656C644E616D650604556E697408446174615479706502
+      18084461746153697A6503FF000549734B6579080F4E65656450726F63657373
+      4E616D650909507265636973696F6E02000453697A6502000001044E616D6506
+      074F776E65724944094669656C644E616D6506074F776E657249440844617461
+      547970650203084461746153697A6502040549734B6579080F4E65656450726F
+      636573734E616D650909507265636973696F6E02000453697A6502000001044E
+      616D6506094F776E6572436F6465094669656C644E616D6506094F776E657243
+      6F64650844617461547970650218084461746153697A6503FF000549734B6579
+      080F4E65656450726F636573734E616D650909507265636973696F6E02000453
+      697A6502000001044E616D6506094F776E65724E616D65094669656C644E616D
+      6506094F776E65724E616D650844617461547970650218084461746153697A65
+      03FF000549734B6579080F4E65656450726F636573734E616D65090950726563
+      6973696F6E02000453697A6502000001044E616D65060A4F776E657253706563
+      73094669656C644E616D65060A4F776E65725370656373084461746154797065
+      0218084461746153697A6503FF000549734B6579080F4E65656450726F636573
+      734E616D650909507265636973696F6E02000453697A6502000001044E616D65
+      06094F776E6572556E6974094669656C644E616D6506094F776E6572556E6974
+      0844617461547970650218084461746153697A6503FF000549734B6579080F4E
+      65656450726F636573734E616D650909507265636973696F6E02000453697A65
+      02000001044E616D650609426173655072696365094669656C644E616D650609
+      4261736550726963650844617461547970650207084461746153697A65020805
+      49734B6579080F4E65656450726F636573734E616D650909507265636973696F
+      6E02000453697A6502000001044E616D65060B42756467657450726963650946
+      69656C644E616D65060B42756467657450726963650844617461547970650207
+      084461746153697A6502080549734B6579080F4E65656450726F636573734E61
+      6D650809507265636973696F6E02000453697A6502000001044E616D65060851
+      75616E74697479094669656C644E616D6506085175616E746974790844617461
+      547970650206084461746153697A6502080549734B6579080F4E65656450726F
+      636573734E616D650909507265636973696F6E02000453697A6502000000}
+  end
+  object sdvMachineDetail: TsdDataView
+    Active = False
+    DataSet = sdsMachineDetail
+    Filtered = False
+    Columns = <
+      item
+        FieldName = 'ID'
+      end
+      item
+        FieldName = 'Code'
+      end
+      item
+        FieldName = 'Name'
+      end
+      item
+        FieldName = 'Specs'
+      end
+      item
+        FieldName = 'Unit'
+      end
+      item
+        FieldName = 'OwnerID'
+      end
+      item
+        FieldName = 'OwnerCode'
+      end
+      item
+        FieldName = 'OwnerName'
+      end
+      item
+        FieldName = 'OwnerSpecs'
+      end
+      item
+        FieldName = 'OwnerUnit'
+      end
+      item
+        FieldName = 'BasePrice'
+      end
+      item
+        FieldName = 'Quantity'
+      end>
+    Left = 256
+    Top = 160
+  end
 end

+ 523 - 60
MainModule/Model/ScMachine.pas

@@ -1,10 +1,16 @@
+{
+  Chenshilong, 2010-9-17 10:54:23 从单价文件库读取机械台班改为从Data\MachineCalcData.dat库读取。
+  Zhangyin 2026-05-28 因为不同省份存在不同编号不同单位的液化气,
+    在补充定额库中新增表MachineMachine,保存机械台班
+    在补充定额库中新增表MachineDetail,保存动力燃料明细
+}
 unit ScMachine;
 
 interface
 
 uses
   SysUtils, Classes, DB, ScFeeTaxDM, ADODB, Forms, Controls,
-  sdDB, sdProvider;
+  sdDB, sdProvider, Variants;
 
 type
   TScMachinePriceRecord = class(TsdDataRecord)
@@ -36,6 +42,7 @@ type
     FYHQ: TsdValue;
     FTRQ: TsdValue;
     FMeiQ: TsdValue;
+    FLibID: TsdValue;
   public
     procedure DoAfterAddFields; override;
     property Code: TsdValue read FCode;
@@ -65,8 +72,42 @@ type
     property KBFee: TsdValue read FKBFee;
     property RGType: TsdValue read FRGType;
     property Visible: TsdValue read FVisible;
+    property LibID: TsdValue read FLibID;
   end;
 
+  TScMachineDetailRecord = class(TsdDataRecord)
+  private
+    FID: TsdValue;
+    FOwnerID: TsdValue;
+    FOwnerCode: TsdValue;
+    FOwnerName: TsdValue;
+    FOwnerSpecs: TsdValue;
+    FOwnerUnit: TsdValue;
+    FCode: TsdValue;
+    FName: TsdValue;
+    FSpecs: TsdValue;
+    FUnit: TsdValue;
+    FBasePrice: TsdValue;
+    FBudgetPrice: TsdValue;
+    FQuantity: TsdValue;
+  protected
+    procedure DoAfterAddFields; override;
+  public
+    property ID: TsdValue read FID;
+    property OwnerID: TsdValue read FOwnerID;
+    property OwnerCode: TsdValue read FOwnerCode;
+    property OwnerName: TsdValue read FOwnerName;
+    property OwnerSpecs: TsdValue read FOwnerSpecs;
+    property OwnerUnit: TsdValue read FOwnerUnit;
+    property Code: TsdValue read FCode;
+    property Name: TsdValue read FName;
+    property Specs: TsdValue read FSpecs;
+    property Units: TsdValue read FUnit;
+    property BasePrice: TsdValue read FBasePrice;
+    property BudgetPrice: TsdValue read FBudgetPrice;
+    property Quantity: TsdValue read FQuantity;
+  end;
+ 
   TMachineEvent = procedure (ARecord: TScMachinePriceRecord) of object;
 
   TMachineData = class(TDataModule)
@@ -76,6 +117,9 @@ type
     sdsMachinePrice: TsdDataSet;
     sdvMachinePrice: TsdDataView;
     sdvMachineLabours: TsdDataView;
+    sapMachineDetail: TsdADOProvider;
+    sdsMachineDetail: TsdDataSet;
+    sdvMachineDetail: TsdDataView;
     procedure DataModuleCreate(Sender: TObject);
     procedure DataModuleDestroy(Sender: TObject);
     procedure sdsMachinePriceGetRecordClass(
@@ -89,6 +133,8 @@ type
     procedure sdvMachineLaboursAfterRecordChanged(ARecord: TsdDataRecord);
     procedure sdsMachinePriceAfterRecordChanged(ARecord: TsdDataRecord);
     procedure sdsMachineLaboursAfterRecordChanged(ARecord: TsdDataRecord);
+    procedure sdsMachineDetailGetRecordClass(
+      var ARecordClass: TsdRecordClass);
   private
     { Private declarations }
     FProject: TObject;
@@ -100,6 +146,11 @@ type
     FidxCode: TsdIndex;
     FOnMachinePriceChanged: TMachineEvent;
     FIsSyncing: Boolean;
+    // 用于显示的燃料列头,用sdvMachinePrice遍历
+    FFuelColumns: TStringList;
+    // 所有有数据的燃料,用sdsMachinePrice遍历
+    FFuelList: TStringList;
+    FOnMachineDetailColumnChanged: TNotifyEvent;
     function GetPrice(AID: Integer): Currency;
     function GetModified: Boolean;
     procedure SetActive(const Value: Boolean);
@@ -113,6 +164,7 @@ type
     // 判断是否需要计算台班的机械
     function IsCalcMachine(AID: Integer): Boolean;
     procedure LoadMachinePrice(ARecord: TsdDataRecord; AKey: string);
+    procedure LoadMachineDetail(ARecord: TsdDataRecord; AKey, AKey2: string);
     procedure LoadMachineLabours(ARecord: TsdDataRecord);
     procedure LoadProperty(AFieldName, AValue: string);
     function GetKeys(AID: Integer): string;
@@ -122,6 +174,9 @@ type
     procedure BeginAllOperate;
     // Connect InterFace
     procedure EndAllOperate;
+    function LoadMachineFromRationLib(AGLJKey: string; var ARationLib: TObject): TsdDataRecord;
+    function AddMachineDetailFromLib(AMachineID: Integer; AGLJKey: string; ARationLib: TObject): Boolean;
+    procedure DeleteMachineDetail(AMachineID: Integer);
   public
     { Public declarations }
     function GetLabourPrice(ALabourCode: Integer): Double;
@@ -154,9 +209,11 @@ type
     procedure SyncMachineLabours(APrice: Double);
     // 同步数据
     procedure SyncData(ATableName, AFieldName: string; ARecord: TsdDataRecord;
-      AKey: string);
+      AKey, AKey2: string);
     // 刷新显示机械
     procedure RefreshMachines;
+    // 是否机械台班相关工料机
+    function IsMachineRelaGL(AKey: string): Boolean;
     // 同步工料机单价
     function SyncGLJPrice(AKey: string; APrice: Currency;
       ACalculateAll: Boolean): Boolean;
@@ -165,9 +222,15 @@ type
     // 获取机械工类型名称
     function LookupMachineLabourName(AType: Integer): string;
     // 是否有机械台班
-    function HasDetail(AID: Integer): Boolean; overload;
-    function HasDetail(ARecord: TScMachinePriceRecord): Boolean; overload;
+    function HasMachine(AID: Integer): Boolean; overload;
+    function HasMachine(ARecord: TScMachinePriceRecord): Boolean; overload;
     function MachineLabourFee(AID: Integer): Currency;
+    // 刷新DLRL列表
+    procedure RefreshFuelColums;
+    // 获得动力燃料数量
+    function GetFuelQuantity(AMachineID: Integer; AName: string): Double;
+    // 赋值动力燃料数量
+    function SetFuelQuantity(AMachineID: Integer; AName: string; AQuantity: Double): Boolean;
     // 是否修改
     property Modified: Boolean read GetModified;
     // 获得机械价格
@@ -178,8 +241,12 @@ type
     property Active: Boolean read FActive write SetActive;
     // 当前机械代号
     property CurrentID: Integer read GetCurrenID;
+    // 动态动力燃料列
+    property FuelColumns: TStringList read FFuelColumns;
     // 机械单价变化事件
     property OnMachinePriceChanged: TMachineEvent read FOnMachinePriceChanged write FOnMachinePriceChanged;
+    // 动力燃料明细变化事件
+    property OnMachineDetailColumnChanged: TNotifyEvent read FOnMachineDetailColumnChanged write FOnMachineDetailColumnChanged;
   end;
 
 implementation
@@ -187,7 +254,7 @@ implementation
 uses
   ScUtils, ScConsts, ScProject, ScProjectGLJ, Math, ScProjBaseDM, ScUnitPriceLibsUnit,
   ScTablesUnit, ScProjectUnitPriceLibsUnit, ScProgressFrm,
-  ScCustomMachineDM;
+  ScCustomMachineDM, ScProjectRationLibsUnit, ScRationLibsUnit;
 
 {$R *.dfm}
 
@@ -222,6 +289,26 @@ begin
   FKBFee := ValueByName('KBFee');
   FRGType := ValueByName('RGType');
   FVisible := ValueByName('Visible');
+  FLibID := ValueByName('LibID');
+end;
+
+{ TScMachineDetailRecord }
+
+procedure TScMachineDetailRecord.DoAfterAddFields;
+begin
+  FID := ValueByName('ID');
+  FOwnerID := ValueByName('OwnerID');
+  FOwnerCode := ValueByName('OwnerCode');
+  FOwnerName := ValueByName('OwnerName');
+  FOwnerSpecs := ValueByName('OwnerSpecs');
+  FOwnerUnit := ValueByName('OwnerUnit');
+  FCode := ValueByName('Code');
+  FName := ValueByName('Name');
+  FSpecs := ValueByName('Specs');
+  FUnit := ValueByName('Unit');
+  FBasePrice := ValueByName('BasePrice');
+  FBudgetPrice := ValueByName('BudgetPrice');
+  FQuantity := ValueByName('Quantity');
 end;
 
 { TScMachineData }
@@ -230,63 +317,98 @@ function TMachineData.Calculate(ARecord: TScMachinePriceRecord): Boolean;
 var
   fValue, fValue1, fValue2, fDLRL, fBBFee, fKBFee: Double;
   fZY, fQY, fCY, fMei, fDian, fShui, fMC, fMeiQ, fYHQ, fTRQ, fRG: Double;
+  fPrice, fFuelTotal: Double;
   ProjectGLJ: TProjectGLJ;
-  iDigit: Integer;
+  I, iDigit: Integer;
+  lstFuel: TList;
+  bMeiQ, bYHQ, bTRQ: Boolean;
+  DetailRec: TScMachineDetailRecord;
+  ProjectGLJRec: TScProjectGLJRecord;
 begin
   Result := False;
   ProjectGLJ := TProjectGLJ(FProjectGLJ);
   iDigit := -TScProject(FProject).DigitManager.BudgetPriceDigit;
-
-  fZY := ARecord.ZY.AsCurrency * ProjectGLJ.BudgetPrice(SZYKeys);
-  fQY := ARecord.QY.AsCurrency * ProjectGLJ.BudgetPrice(SQYKeys);
-  fCY := ARecord.CY.AsCurrency * ProjectGLJ.BudgetPrice(SCYKeys);
-  fMei := ARecord.Mei.AsCurrency * ProjectGLJ.BudgetPrice(SMeiKeys);
-  fDian := ARecord.Dian.AsCurrency * ProjectGLJ.BudgetPrice(SDianKeys);
-  fShui := ARecord.Shui.AsCurrency * ProjectGLJ.BudgetPrice(SShuiKeys);
-  fMC := ARecord.MC.AsCurrency * ProjectGLJ.BudgetPrice(SMCKeys);
-  fMeiQ := ARecord.MeiQ.AsCurrency * ProjectGLJ.BudgetPrice(SMeiQKeys);
-  fYHQ := ARecord.YHQ.AsCurrency * ProjectGLJ.BudgetPrice(SYHQKeys);
-  fTRQ := ARecord.TRQ.AsCurrency * ProjectGLJ.BudgetPrice(STRQKeys);
-  fRG := ARecord.RG.AsCurrency * GetLabourPrice(ARecord.RGType.AsInteger);
-  fDLRL :=
-    ScRoundTo(fZY, iDigit) +
-    ScRoundTo(fQY, iDigit) +
-    ScRoundTo(fCY, iDigit) +
-    ScRoundTo(fMei, iDigit) +
-    ScRoundTo(fDian, iDigit) +
-    ScRoundTo(fShui, iDigit) +
-    ScRoundTo(fMC, iDigit) +
-    ScRoundTo(fMeiQ, iDigit) +
-    ScRoundTo(fYHQ, iDigit) +
-    ScRoundTo(fTRQ, iDigit);
-  fBBFee :=
-    ScRoundTo(ARecord.ZJ.AsCurrency, iDigit) +
-    ScRoundTo(ARecord.DXL.AsCurrency, iDigit) +
-    ScRoundTo(ARecord.JCXL.AsCurrency, iDigit) +
-    ScRoundTo(ARecord.AZFZ.AsCurrency, iDigit);
-  fKBFee :=
-    ScRoundTo(fRG, iDigit) +
-    fDLRL +
-    ScRoundTo(ARecord.YLCC.AsCurrency, iDigit);
-
-  fValue := fBBFee * TScProject(FProject).MachineBBFeeRate + fKBFee;
-  fValue := ScRoundTo(fValue, iDigit);
-
-  if (ARecord.Price.AsCurrency <> fValue) or (ARecord.DLRL.AsCurrency <> fDLRL) or
-     (ARecord.BBFee.AsCurrency <> fBBFee) or (ARecord.KBFee.AsCurrency <> fKBFee)
-    then
-  begin
-    ARecord.BeginUpdate;
-    try
-      ARecord.DLRL.AsCurrency := fDLRL;
-      ARecord.BBFee.AsCurrency := fBBFee;
-      ARecord.KBFee.AsCurrency := fKBFee;
-      ARecord.Price.AsCurrency := fValue;
-    finally
-      ARecord.EndUpdate;
+  bMeiQ := False;
+  bYHQ := False;
+  bTRQ := False;
+  fMeiQ := 0;
+  fYHQ := 0;
+  fTRQ := 0;
+  lstFuel := TList.Create;
+  try
+    fRG := ARecord.RG.AsCurrency * GetLabourPrice(ARecord.RGType.AsInteger);
+    // 动力燃料
+    fZY := ARecord.ZY.AsCurrency * ProjectGLJ.BudgetPrice(SZYKeys);
+    fQY := ARecord.QY.AsCurrency * ProjectGLJ.BudgetPrice(SQYKeys);
+    fCY := ARecord.CY.AsCurrency * ProjectGLJ.BudgetPrice(SCYKeys);
+    fMei := ARecord.Mei.AsCurrency * ProjectGLJ.BudgetPrice(SMeiKeys);
+    fDian := ARecord.Dian.AsCurrency * ProjectGLJ.BudgetPrice(SDianKeys);
+    fShui := ARecord.Shui.AsCurrency * ProjectGLJ.BudgetPrice(SShuiKeys);
+    fMC := ARecord.MC.AsCurrency * ProjectGLJ.BudgetPrice(SMCKeys);
+    // 新增动力燃料单独计算
+    sdsMachineDetail.RecordsByKey('idxOwner', ARecord.ID.AsInteger, lstFuel);
+    fFuelTotal := 0;
+    for I := 0 to lstFuel.Count - 1 do
+    begin
+      DetailRec := TScMachineDetailRecord(lstFuel[I]);
+      fPrice := ProjectGLJ.BudgetPrice(DetailRec.ID.AsInteger);
+      fFuelTotal := fFuelTotal + RoundTo(DetailRec.Quantity.AsFloat * fPrice, iDigit);
+      if SameText(DetailRec.Name.AsString, SNMeiQCode) then
+        bMeiQ := True;
+      if SameText(DetailRec.Name.AsString, SNYHQCode) then
+        bYHQ := True;
+      if SameText(DetailRec.Name.AsString, SNTRQCode) then
+        bTRQ := True;
     end;
+    // 煤气/液化气/天然气可能存在并行,以MachineDetail表为准
+    if not bMeiQ then
+      fMeiQ := ARecord.MeiQ.AsCurrency * ProjectGLJ.BudgetPrice(SMeiQKeys);
+    if not bYHQ then
+      fYHQ := ARecord.YHQ.AsCurrency * ProjectGLJ.BudgetPrice(SYHQKeys);
+    if not bTRQ then
+      fTRQ := ARecord.TRQ.AsCurrency * ProjectGLJ.BudgetPrice(STRQKeys);
+    fDLRL :=
+      ScRoundTo(fZY, iDigit) +
+      ScRoundTo(fQY, iDigit) +
+      ScRoundTo(fCY, iDigit) +
+      ScRoundTo(fMei, iDigit) +
+      ScRoundTo(fDian, iDigit) +
+      ScRoundTo(fShui, iDigit) +
+      ScRoundTo(fMC, iDigit) +
+      ScRoundTo(fMeiQ, iDigit) +
+      ScRoundTo(fYHQ, iDigit) +
+      ScRoundTo(fTRQ, iDigit) +
+      fFuelTotal;
+    fBBFee :=
+      ScRoundTo(ARecord.ZJ.AsCurrency, iDigit) +
+      ScRoundTo(ARecord.DXL.AsCurrency, iDigit) +
+      ScRoundTo(ARecord.JCXL.AsCurrency, iDigit) +
+      ScRoundTo(ARecord.AZFZ.AsCurrency, iDigit);
+    fKBFee :=
+      ScRoundTo(fRG, iDigit) +
+      fDLRL +
+      ScRoundTo(ARecord.YLCC.AsCurrency, iDigit);
+
+    fValue := fBBFee * TScProject(FProject).MachineBBFeeRate + fKBFee;
+    fValue := ScRoundTo(fValue, iDigit);
+
+    if (ARecord.Price.AsCurrency <> fValue) or (ARecord.DLRL.AsCurrency <> fDLRL) or
+       (ARecord.BBFee.AsCurrency <> fBBFee) or (ARecord.KBFee.AsCurrency <> fKBFee)
+      then
+    begin
+      ARecord.BeginUpdate;
+      try
+        ARecord.DLRL.AsCurrency := fDLRL;
+        ARecord.BBFee.AsCurrency := fBBFee;
+        ARecord.KBFee.AsCurrency := fKBFee;
+        ARecord.Price.AsCurrency := fValue;
+      finally
+        ARecord.EndUpdate;
+      end;
+    end;
+  finally
+    lstFuel.Free;
   end;
-
   if ProjectGLJ.BudgetPrice(ARecord.ID.AsInteger) <> fValue then
   begin
     if ARecord.Price.AsCurrency <> 0 then
@@ -341,9 +463,11 @@ begin
   FProjectGLJ := AProjectGLJ;
   FProject := TProjectGLJ(AProjectGLJ).Project;
   sapMachinePrice.Connection := TScProject(FProject).ADOConnection;
+  sapMachineDetail.Connection := TScProject(FProject).ADOConnection;
   sapMachineLabours.Connection := TScProject(FProject).ADOConnection;
   FidxID := sdsMachinePrice.AddIndex('idxID', SID);
   FidxCode := sdsMachinePrice.AddIndex('idxCode', Format('%s;%s;%s;%s', [SCode, SName, SSpecs, SUnit]));
+  sdsMachineDetail.AddIndex('idxOwner', Format('%s;%s', [SOwnerID, SCode]));
   sdvMachinePrice.IndexName := 'idxCode';
 end;
 
@@ -400,6 +524,8 @@ var
   strKeys, strCode, strName, strSpecs, strUnit: string;
   Rec: TScMachinePriceRecord;
   DataRec: TsdDataRecord;
+  objLib: TObject;
+  RationLib: TScRationLib;
 begin
   Result := False;
   Rec := LocateMachine(AID);
@@ -407,7 +533,12 @@ begin
   begin
     strKeys := GetKeys(AID);
     ResolveGLJKeys(strKeys, strCode, strName, strSpecs, strUnit);
-    DataRec := CustomMachine.FindMachineData(strKeys);
+    // 先查找定额库中是否有此机械台班
+    DataRec := LoadMachineFromRationLib(strKeys, objLib);
+    RationLib := TScRationLib(objLib);
+    // 所有定额库中找不到,则到MachineCalcData.dat中找部颁台班
+    if DataRec = nil then
+      DataRec := CustomMachine.FindMachineData(strKeys);
     if DataRec <> nil then
     begin
       TProjectGLJ(FProjectGLJ).AddMachineRelaGL(0);
@@ -435,6 +566,13 @@ begin
         Rec.TRQ.AsCurrency   := DataRec.ValueByName(STRQ).AsCurrency;
         Rec.YLCC.AsCurrency := GetFeeTax(strKeys);
         Rec.RGType.AsInteger := DataRec.ValueByName(SRGType).AsInteger;
+        if RationLib <> nil then
+        begin
+          Rec.LibID.AsInteger := RationLib.ID;
+          AddMachineDetailFromLib(AID, strKeys, RationLib);
+        end
+        else
+          Rec.LibID.AsInteger := -1;
       finally
         Rec.EndUpdate;
       end;
@@ -475,6 +613,7 @@ begin
       Result := True;
     end;
   end;
+  RefreshFuelColums;
 end;
 
 procedure TMachineData.SyncAllFeeTax;
@@ -496,7 +635,10 @@ begin
   Result := False;
   Rec := LocateMachine(AID);
   if Rec <> nil then
+  begin
+    DeleteMachineDetail(Rec.ID.AsInteger);
     Result := sdsMachinePrice.Remove(Rec);
+  end;
 end;
 
 function TMachineData.GetModified: Boolean;
@@ -514,12 +656,16 @@ begin
   try
     FidxCode.RecordsByKey(0, List);
     for I := 0 to List.Count - 1 do
+    begin
+      DeleteMachineDetail(TScMachinePriceRecord(List[I]).ID.AsInteger);
       sdsMachinePrice.Remove(TsdDataRecord(List[I]));
+    end;
   finally
     List.Free;
   end;
 
   sdsMachinePrice.Save;
+  sdsMachineDetail.Save;
   sdsMachineLabours.Save;
 end;
 
@@ -537,11 +683,15 @@ procedure TMachineData.DataModuleCreate(Sender: TObject);
 begin
   FFeeTaxDM := TFeeTaxDM.Create(nil);
   FIsSyncing := False;
+  FFuelColumns := TStringList.Create;
+  FFuelList := TStringList.Create;
 end;
 
 procedure TMachineData.DataModuleDestroy(Sender: TObject);
 begin
   FFeeTaxDM.Free;
+  FFuelColumns.Free;
+  FFuelList.Free;
 end;
 
 procedure TMachineData.SetActive(const Value: Boolean);
@@ -555,13 +705,18 @@ begin
 
     sdsMachinePrice.Open;
     sdvMachinePrice.Open;
+    sdsMachineDetail.Open;
+    sdvMachineDetail.Open;
 
     FActive := Value;
+    RefreshFuelColums;
   end
   else
   begin
     sdsMachinePrice.Close;
     sdvMachinePrice.Close;
+    sdsMachineDetail.Close;
+    sdvMachineDetail.Close;
     sdsMachineLabours.Close;
     sdvMachineLabours.Close;
     FActive := Value;
@@ -931,6 +1086,7 @@ begin
     sdvMachinePrice.Filter := Format('Code<>''%s''', [SSmallMachineFeeCode]);
 
   sdvMachinePrice.Filtered := True;
+  RefreshFuelColums;
 end;
 
 procedure TMachineData.BeginAllOperate;
@@ -993,6 +1149,28 @@ begin
     TProjectGLJ(FProjectGLJ).LocateCurrentGLJ(TScMachinePriceRecord(ARecord).ID.AsInteger);
 end;
 
+function TMachineData.IsMachineRelaGL(AKey: string): Boolean;
+var
+  I: Integer;
+  strCode, strName, strSpecs, strUnit: string;
+begin
+  Result := False;
+  for I := Low(MachineRelaGLKeys) to High(MachineRelaGLKeys) do
+    if AKey = MachineRelaGLKeys[I] then
+    begin
+      Result := True;
+      Break;
+    end;
+  if Result then Exit;
+  ResolveGLJKeys(AKey, strCode, strName, strSpecs, strUnit);
+  for I := 0 to FFuelList.Count - 1 do
+    if SameText(strName, FFuelList.Names[I]) then
+    begin
+      Result := True;
+      Break;
+    end;
+end;
+
 function TMachineData.SyncGLJPrice(AKey: string; APrice: Currency;
   ACalculateAll: Boolean): Boolean;
 begin
@@ -1098,6 +1276,51 @@ begin
   end;
 end;
 
+procedure TMachineData.LoadMachineDetail(ARecord: TsdDataRecord;
+  AKey, AKey2: string);
+var
+  iID, iOwnerID: Integer;
+  strCode, strName, strSpecs, strUnit: string;
+  DetailRec: TScMachineDetailRecord;
+begin
+  if not ResolveGLJKeys(AKey, strCode, strName, strSpecs, strUnit) then Exit;
+  iID := TProjectGLJ(FProjectGLJ).KeysToID(AKey);
+  iOwnerID := TProjectGLJ(FProjectGLJ).KeysToID(AKey2);;
+  if (iID < 0) or (iOwnerID < 0) then Exit;
+  DetailRec := TScMachineDetailRecord(sdsMachineDetail.Locate(Format('%s;%s', [SID, SOwnerID]), VarArrayOf([iID, iOwnerID])));
+  if DetailRec <> nil then
+  begin
+    // 消耗量,单价相等,无需同步
+    if (DetailRec.Quantity.AsFloat = ARecord.ValueByName(SQuantity).AsFloat) and
+      (DetailRec.BasePrice.AsCurrency = ARecord.ValueByName(SBasePrice).AsCurrency) and
+      (DetailRec.BudgetPrice.AsCurrency = ARecord.ValueByName(SBudgetPrice).AsCurrency) then
+      Exit;
+    DetailRec.BeginUpdate;
+  end
+  else
+    DetailRec := TScMachineDetailRecord(sdsMachineDetail.Add(True));
+  try
+    if DetailRec.Inserting then
+    begin
+      DetailRec.ID.AsInteger := iID;
+      DetailRec.Code.AsString := strCode;
+      DetailRec.Name.AsString := strName;
+      DetailRec.Specs.AsString := strSpecs;
+      DetailRec.Units.AsString := strUnit;
+      DetailRec.OwnerID.AsInteger := iOwnerID;
+      DetailRec.OwnerCode.AsString := ARecord.ValueByName(SOwnerCode).AsString;
+      DetailRec.OwnerName.AsString := ARecord.ValueByName(SOwnerName).AsString;
+      DetailRec.OwnerSpecs.AsString := ARecord.ValueByName(SOwnerSpecs).AsString;
+      DetailRec.OwnerUnit.AsString := ARecord.ValueByName(SOwnerUnit).AsString;
+    end;
+    DetailRec.Quantity.AsFloat := ARecord.ValueByName(SQuantity).AsFloat;
+    DetailRec.BasePrice.AsCurrency := ARecord.ValueByName(SBasePrice).AsCurrency;
+    DetailRec.BudgetPrice.AsCurrency := ARecord.ValueByName(SBudgetPrice).AsCurrency;
+  finally
+    DetailRec.EndUpdate;
+  end;
+end;
+
 procedure TMachineData.LoadMachineLabours(ARecord: TsdDataRecord);
 var
   iCode: Integer;
@@ -1116,12 +1339,14 @@ begin
 end;
 
 procedure TMachineData.SyncData(ATableName, AFieldName: string;
-  ARecord: TsdDataRecord; AKey: string);
+  ARecord: TsdDataRecord; AKey, AKey2: string);
 begin
   FIsSyncing := True;
   try
     if SameText(ATableName, SMachinePrice) then
       LoadMachinePrice(ARecord, AKey)
+    else if SameText(ATableName, SMachineDetail) then
+      LoadMachineDetail(ARecord, AKey, AKey2)
     else if SameText(ATableName, SMachineLabours) then
       LoadMachineLabours(ARecord)
     else if SameText(ATableName, SProperty) then
@@ -1178,15 +1403,15 @@ begin
     Result := CombineGLJKeys(ProjectGLJRec);
 end;
 
-function TMachineData.HasDetail(AID: Integer): Boolean;
+function TMachineData.HasMachine(AID: Integer): Boolean;
 var
   Rec: TScMachinePriceRecord;
 begin
   Rec := LocateMachine(AID);
-  Result := HasDetail(Rec);
+  Result := HasMachine(Rec);
 end;
 
-function TMachineData.HasDetail(ARecord: TScMachinePriceRecord): Boolean;
+function TMachineData.HasMachine(ARecord: TScMachinePriceRecord): Boolean;
 begin
   Result := False;
   if ARecord = nil then Exit;
@@ -1204,4 +1429,242 @@ begin
     Result := Rec.RG.AsCurrency * GetLabourPrice(Rec.RGType.AsInteger);
 end;
 
+function TMachineData.LoadMachineFromRationLib(
+  AGLJKey: string; var ARationLib: TObject): TsdDataRecord;
+var
+  I, J, K: Integer;
+  ProjectRationLib: TScProjectRationLib;
+  RationLib: TScRationLib;
+  DetailRec: TsdDataRecord;
+begin
+  Result := nil;
+  ARationLib := nil;
+  // 查找定额库中有没有指定机械台班
+  for I := 0 to TScProject(FProject).RationLibs.Count - 1 do
+  begin
+    ProjectRationLib := TScProject(FProject).RationLibs.FindLib(I);
+    if ProjectRationLib.Active and ProjectRationLib.Selected then
+    begin
+      RationLib := ProjectRationLib.Lib;
+      if RationLib.sdsMachinePrice.Active then
+      begin
+        DetailRec := LocateByKeys(RationLib.sdsMachinePrice, AGLJKey);
+        if DetailRec <> nil then
+        begin
+          ARationLib := RationLib;
+          Result := DetailRec;
+          Break;
+        end;
+      end;
+    end;
+  end;
+end;
+
+function TMachineData.AddMachineDetailFromLib(
+  AMachineID: Integer; AGLJKey: string; ARationLib: TObject): Boolean;
+var
+  I, iLibID: Integer;
+  LibDetailRecord, DetailRecord: TsdDataRecord;
+  ProjectGLJRecord: TScProjectGLJRecord;
+  RationLib: TScRationLib;
+  lstDetail: TList;
+  strCode, strName, strSpecs, strUnit, strKey: string;
+begin
+  Result := False;
+  RationLib := TScRationLib(ARationLib);
+  iLibID := TScProject(FProject).RationLibs.IDByLibID(RationLib.ID);
+  lstDetail := TList.Create;
+  try
+    // 删除已有记录
+    DeleteMachineDetail(AMachineID);
+    // 查找定额库中台班明细
+    ResolveGLJKeys(AGLJKey, strCode, strName, strSpecs, strUnit);
+    RationLib.sdsMachineDetail.FilterBy(
+      Format('OwnerCode=''%s'' AND OwnerName=''%s'' AND OwnerSpecs=''%s'' AND OwnerUnit=''%s''', [strCode, strName, strSpecs, strUnit]),
+      lstDetail, 'OwnerCode');
+    for I := 0 to lstDetail.Count - 1 do
+    begin
+      LibDetailRecord := TsdDataRecord(lstDetail[I]);
+      strKey := CombineGLJKeys(LibDetailRecord);
+      ProjectGLJRecord := TProjectGLJ(FProjectGLJ).AddGLJFromLibRec(iLibID, strKey);
+      DetailRecord := sdsMachineDetail.Add(True);
+      try
+        DetailRecord.ValueByName(SID).AsInteger := ProjectGLJRecord.ID.AsInteger;
+        DetailRecord.ValueByName(SOwnerID).AsInteger := AMachineID;
+        DetailRecord.ValueByName(SCode).AsString := LibDetailRecord.ValueByName(SCode).AsString;
+        DetailRecord.ValueByName(SName).AsString := LibDetailRecord.ValueByName(SName).AsString;
+        DetailRecord.ValueByName(SSpecs).AsString := LibDetailRecord.ValueByName(SSpecs).AsString;
+        DetailRecord.ValueByName(SUnit).AsString := LibDetailRecord.ValueByName(SUnit).AsString;
+        DetailRecord.ValueByName(SOwnerCode).AsString := LibDetailRecord.ValueByName(SOwnerCode).AsString;
+        DetailRecord.ValueByName(SOwnerName).AsString := LibDetailRecord.ValueByName(SOwnerName).AsString;
+        DetailRecord.ValueByName(SOwnerSpecs).AsString := LibDetailRecord.ValueByName(SOwnerSpecs).AsString;
+        DetailRecord.ValueByName(SOwnerUnit).AsString := LibDetailRecord.ValueByName(SOwnerUnit).AsString;
+        DetailRecord.ValueByName(SQuantity).AsFloat := LibDetailRecord.ValueByName(SQuantity).AsFloat;
+        DetailRecord.ValueByName(SBasePrice).AsCurrency := LibDetailRecord.ValueByName(SBasePrice).AsCurrency;
+        DetailRecord.ValueByName(SBudgetPrice).AsCurrency := ProjectGLJRecord.BudgetPrice.AsCurrency;
+      finally
+        DetailRecord.EndUpdate;
+      end;
+    end;
+  finally
+    lstDetail.Free;
+  end;
+end;
+
+procedure TMachineData.DeleteMachineDetail(AMachineID: Integer);
+var
+  I: Integer;
+  lstDetail: TList;
+begin
+  lstDetail := TList.Create;
+  try
+    sdsMachineDetail.RecordsByKey('idxOwner', AMachineID, lstDetail);
+    for I := 0 to lstDetail.Count - 1 do
+      sdsMachineDetail.Remove(TsdDataRecord(lstDetail[I]));
+  finally
+    lstDetail.Free;
+  end;
+end;
+
+// 刷新动力燃料列定义(不包含部颁7种)
+procedure TMachineData.RefreshFuelColums;
+var
+  I, iFieldNo: Integer;
+  MachineRec: TScMachinePriceRecord;
+  DetailRec: TScMachineDetailRecord;
+  strKey, strName, strField: string;
+  bMeiQ, bYHQ, bTRQ, bView: Boolean;
+  lstFuel, lstFuelView: TStringList;
+begin
+  iFieldNo := 0;
+  bMeiQ := False;
+  bYHQ := False;
+  bTRQ := False;
+  lstFuel := TStringList.Create;
+  lstFuelView := TStringList.Create;
+  try
+    // 从sdsMachinePrice中检查煤气/天然气/液化气列
+    for I := 0 to sdsMachinePrice.RecordCount - 1 do
+    begin
+      MachineRec := TScMachinePriceRecord(sdsMachinePrice[I]);
+      if MachineRec.MeiQ.AsCurrency <> 0 then
+        bMeiQ := True;
+      if MachineRec.YHQ.AsCurrency <> 0 then
+        bYHQ := True;
+      if MachineRec.TRQ.AsCurrency <> 0 then
+        bTRQ := True;
+      if bMeiQ and bYHQ and bTRQ then
+        Break;
+    end;
+    if bMeiQ then
+      lstFuel.Add(SMeiQFieldTitle);
+    if bYHQ then
+      lstFuel.Add(SYHQFieldTitle);
+    if bTRQ then
+      lstFuel.Add(STRQFieldTitle);
+    // 从sdvMachinePrice中检查煤气/天然气/液化气列
+    for I := 0 to sdvMachinePrice.RecordCount - 1 do
+    begin
+      MachineRec := TScMachinePriceRecord(sdvMachinePrice[I]);
+      if MachineRec.MeiQ.AsCurrency <> 0 then
+        bMeiQ := True;
+      if MachineRec.YHQ.AsCurrency <> 0 then
+        bYHQ := True;
+      if MachineRec.TRQ.AsCurrency <> 0 then
+        bTRQ := True;
+      if bMeiQ and bYHQ and bTRQ then
+        Break;
+    end;
+    if bMeiQ then
+      lstFuelView.Add(SMeiQFieldTitle);
+    if bYHQ then
+      lstFuelView.Add(SYHQFieldTitle);
+    if bTRQ then
+      lstFuelView.Add(STRQFieldTitle);
+    // 从MachinePrice中检查煤气/天然气/液化气及新增列
+    for I := 0 to sdsMachineDetail.RecordCount - 1 do
+    begin
+      DetailRec := TScMachineDetailRecord(sdsMachineDetail[I]);
+      // 检查当前机械是否显示
+      bView := sdvMachinePrice.Locate(SID, DetailRec.OwnerID.AsInteger) <> nil;
+      strKey := CombineGLJKeys(DetailRec);
+      strName := DetailRec.Name.AsString;
+      // 煤气/天然气/液化气仍然需要检查
+      if SameText(strName, SNMeiQCode) then
+      begin
+        if lstFuel.IndexOf(SMeiQFieldTitle) < 0 then
+          lstFuel.Add(SMeiQFieldTitle);
+        if bView and (lstFuelView.IndexOf(SMeiQFieldTitle) < 0) then
+          lstFuelView.Add(SMeiQFieldTitle);
+      end
+      else if SameText(strName, SNYHQCode) then
+      begin
+        if lstFuel.IndexOf(SYHQFieldTitle) < 0 then
+          lstFuel.Add(SYHQFieldTitle);
+        if bView and (lstFuelView.IndexOf(SYHQFieldTitle) < 0) then
+          lstFuelView.Add(SYHQFieldTitle);
+      end
+      else if SameText(strName, SNTRQCode) then
+      begin
+        if lstFuel.IndexOf(STRQFieldTitle) < 0 then
+          lstFuel.Add(STRQFieldTitle);
+        if bView and (lstFuelView.IndexOf(STRQFieldTitle) < 0) then
+          lstFuelView.Add(STRQFieldTitle);
+      end
+      // 未定义过的以Fuel+数字作为字段名
+      else
+      begin
+        if lstFuel.IndexOfName(strName) < 0 then
+        begin
+          Inc(iFieldNo);
+          strField := SFuel + IntToStr(iFieldNo);
+          lstFuel.Add(Format('%s=%s', [strName, strField]));
+          if bView then
+            lstFuelView.Add(Format('%s=%s', [strName, strField]));
+        end;
+      end
+    end;
+
+    if (lstFuel.Count <> FFuelList.Count) or (not SameText(lstFuel.Text, FFuelList.Text))then
+      FFuelList.Assign(lstFuel);
+    if (lstFuelView.Count <> FFuelColumns.Count) or (not SameText(lstFuelView.Text, FFuelColumns.Text))then
+    begin
+      FFuelColumns.Assign(lstFuelView);
+      if Assigned(FOnMachineDetailColumnChanged) then
+        FOnMachineDetailColumnChanged(Self);
+    end;
+  finally
+    lstFuel.Free;
+    lstFuelView.Free;
+  end;
+end;
+
+function TMachineData.GetFuelQuantity(AMachineID: Integer;
+  AName: string): Double;
+var
+  Rec: TScMachineDetailRecord;
+begin
+  Result := 0;
+  Rec := TScMachineDetailRecord(sdsMachineDetail.Locate('OwnerID;Name', VarArrayOf([AMachineID, AName])));
+  if Rec <> nil then
+    Result := Rec.Quantity.AsFloat;
+end;
+
+function TMachineData.SetFuelQuantity(AMachineID: Integer; AName: string;
+  AQuantity: Double): Boolean;
+var
+  Rec: TScMachineDetailRecord;
+begin
+  Rec := TScMachineDetailRecord(sdsMachineDetail.Locate('OwnerID;Name', VarArrayOf([AMachineID, AName])));
+  Result := Rec <> nil;
+  if Result then
+    Rec.Quantity.AsFloat := AQuantity;
+end;
+
+procedure TMachineData.sdsMachineDetailGetRecordClass(
+  var ARecordClass: TsdRecordClass);
+begin
+  ARecordClass := TScMachineDetailRecord;
+end;
+
 end.

+ 143 - 27
MainModule/Model/ScProjectGLJ.pas

@@ -11,7 +11,7 @@ unit ScProjectGLJ;
 interface
 
 uses
-  SysUtils, Classes, DB, DBClient, Forms, Controls, Dialogs,
+  SysUtils, Classes, DB, DBClient, Forms, Controls, Dialogs, Messages, ScMessage,
   ScUtils, ScMaterial, Windows, ZJLists, ScFeeTaxDM, ScMachine, ADODB, ScElectricityCalcDM,
   sdDB, sdProvider;
 
@@ -306,6 +306,7 @@ type
     procedure EndSilentOnChange;
     procedure SetOnGLJChangedForBillsGLJ(const Value: TsdRecordEvent);
     procedure DoOnGLJChangedForBillsGLJ(ARecord: TsdDataRecord);
+    procedure SCMAddRationLib(var Message: TMessage); message SCM_AddRationLib;
   public
     { Public declarations }
     // 汇总计算
@@ -633,9 +634,33 @@ begin
   FPriceDigit := TScProject(FProject).DigitManager.BudgetPriceDigit;
 end;
 
+type
+  PGLJAmount = ^TGLJAmount;
+  TGLJAmount = record
+    ID: Integer;
+    Amount: Double;
+    TenderAmount: Double;
+  end;
+
 procedure TProjectGLJ.GatherMachineRelaGL;
 var
-  I, iDigit: Integer;
+  lstFuelAmount: TList;
+
+  function FindFuel(AID: Integer): PGLJAmount;
+  var
+    I: Integer;
+  begin
+    Result := nil;
+    for I := 0 to lstFuelAmount.Count - 1 do
+      if PGLJAmount(lstFuelAmount[I]).ID = AID then
+      begin
+        Result := lstFuelAmount[I];
+        Break;
+      end;
+  end;
+
+var
+  I, J, iDigit: Integer;
   RelaGL: array [0..10] of Currency;
   RelaTenderGL: array [0..10] of Currency;
   GLJAmount, TenderGLJAmount: Currency;
@@ -644,6 +669,10 @@ var
   MasterItem: TsdMasterItem;
   GLJRec: TScProjectGLJRecord;
   MachineRec: TScMachinePriceRecord;
+  lstFuel: TList;
+  pFuel: PGLJAmount;
+  MachineDetailRec: TScMachineDetailRecord;
+  bMeiQ, bYHQ, bTRQ: Boolean;
 begin
   iDigit := TScProject(FProject).DigitManager.GLJQuantityDigit;
   ZeroMemory(@RelaGL[0], SizeOf(RelaGL));
@@ -652,6 +681,8 @@ begin
   MachineList := TList.Create;
   Map := TsdListMasterDetailMap.Create;
   try
+    lstFuel := TList.Create;
+    lstFuelAmount := TList.Create;
     FidxType.RecordsByKey(GLJ_Machine, GLJList);
     FMachineData.sdsMachinePrice.RecordsByKey('idxID', Null, MachineList);
     Map.MasterField := SID;
@@ -661,6 +692,9 @@ begin
     Map.CreateMap;
     for I := 0 to Map.Count - 1 do
     begin
+      bMeiQ := False;
+      bYHQ := False;
+      bTRQ := False;
       MasterItem := Map[I];
       if MasterItem.Count = 0 then
         Continue;
@@ -668,6 +702,33 @@ begin
       GLJAmount := GLJRec.Amount.AsCurrency;
       TenderGLJAmount := GLJRec.TenderAmount.AsCurrency;
       MachineRec := TScMachinePriceRecord(MasterItem[0]);
+      // 动态燃料
+      FMachineData.sdsMachineDetail.RecordsByKey('idxOwner', MachineRec.ID.AsInteger, lstFuel);
+      for J := 0 to lstFuel.Count - 1 do
+      begin
+        MachineDetailRec := TScMachineDetailRecord(lstFuel[J]);
+        pFuel := FindFuel(MachineDetailRec.ID.AsInteger);
+        if not Assigned(pFuel) then
+        begin
+          New(pFuel);
+          lstFuelAmount.Add(pFuel);
+          pFuel^.ID := MachineDetailRec.ID.AsInteger;
+          pFuel^.Amount := MachineDetailRec.Quantity.AsFloat * GLJAmount;
+          pFuel^.TenderAmount := MachineDetailRec.Quantity.AsFloat * TenderGLJAmount;
+        end
+        else
+        begin
+          pFuel^.Amount := pFuel^.Amount + MachineDetailRec.Quantity.AsFloat * GLJAmount;
+          pFuel^.TenderAmount := pFuel^.TenderAmount + MachineDetailRec.Quantity.AsFloat * TenderGLJAmount;
+        end;
+        if SameText(MachineDetailRec.Name.AsString, SNMeiQCode) then
+          bMeiQ := True;
+        if SameText(MachineDetailRec.Name.AsString, SNYHQCode) then
+          bYHQ := True;
+        if SameText(MachineDetailRec.Name.AsString, SNTRQCode) then
+          bTRQ := True;
+      end;
+      // 静态燃料
       RelaGL[0] := RelaGL[0] + MachineRec.RG.AsCurrency * GLJAmount;
       RelaGL[1] := RelaGL[1] + MachineRec.ZY.AsCurrency * GLJAmount;
       RelaGL[2] := RelaGL[2] + MachineRec.QY.AsCurrency * GLJAmount;
@@ -676,9 +737,13 @@ begin
       RelaGL[5] := RelaGL[5] + MachineRec.Dian.AsCurrency * GLJAmount;
       RelaGL[6] := RelaGL[6] + MachineRec.Shui.AsCurrency * GLJAmount;
       RelaGL[7] := RelaGL[7] + MachineRec.MC.AsCurrency * GLJAmount;
-      RelaGL[8] := RelaGL[8] + MachineRec.MeiQ.AsCurrency * GLJAmount;
-      RelaGL[9] := RelaGL[9] + MachineRec.YHQ.AsCurrency * GLJAmount;
-      RelaGL[10] := RelaGL[10] + MachineRec.TRQ.AsCurrency * GLJAmount;
+      // 有动态则忽略静态
+      if not bMeiQ then
+        RelaGL[8] := RelaGL[8] + MachineRec.MeiQ.AsCurrency * GLJAmount;
+      if not bYHQ then
+        RelaGL[9] := RelaGL[9] + MachineRec.YHQ.AsCurrency * GLJAmount;
+      if not bTRQ then
+        RelaGL[10] := RelaGL[10] + MachineRec.TRQ.AsCurrency * GLJAmount;
 
       RelaTenderGL[0] := RelaTenderGL[0] + MachineRec.RG.AsCurrency * TenderGLJAmount;
       RelaTenderGL[1] := RelaTenderGL[1] + MachineRec.ZY.AsCurrency * TenderGLJAmount;
@@ -688,30 +753,46 @@ begin
       RelaTenderGL[5] := RelaTenderGL[5] + MachineRec.Dian.AsCurrency * TenderGLJAmount;
       RelaTenderGL[6] := RelaTenderGL[6] + MachineRec.Shui.AsCurrency * TenderGLJAmount;
       RelaTenderGL[7] := RelaTenderGL[7] + MachineRec.MC.AsCurrency * TenderGLJAmount;
-      RelaTenderGL[8] := RelaTenderGL[8] + MachineRec.MeiQ.AsCurrency * TenderGLJAmount;
-      RelaTenderGL[9] := RelaTenderGL[9] + MachineRec.YHQ.AsCurrency * TenderGLJAmount;
-      RelaTenderGL[10] := RelaTenderGL[10] + MachineRec.TRQ.AsCurrency * TenderGLJAmount;
+      // 有动态则忽略静态
+      if not bMeiQ then
+        RelaTenderGL[8] := RelaTenderGL[8] + MachineRec.MeiQ.AsCurrency * TenderGLJAmount;
+      if not bYHQ then
+        RelaTenderGL[9] := RelaTenderGL[9] + MachineRec.YHQ.AsCurrency * TenderGLJAmount;
+      if not bTRQ then
+        RelaTenderGL[10] := RelaTenderGL[10] + MachineRec.TRQ.AsCurrency * TenderGLJAmount;
+    end;
+    // 汇总静态燃料
+    for I := Low(MachineRelaGLKeys) to High(MachineRelaGLKeys) do
+    begin
+      GLJRec := LocateGLJ(MachineRelaGLKeys[I]);
+      if GLJRec <> nil then
+      begin
+        GLJRec.BeginUpdate;
+        try
+          GLJRec.Amount.AsCurrency := GLJRec.Amount.AsCurrency + ScRoundTo(RelaGL[I], -iDigit);
+          GLJRec.TenderAmount.AsCurrency := GLJRec.TenderAmount.AsCurrency + ScRoundTo(RelaTenderGL[I], -iDigit);
+        finally
+          GLJRec.EndUpdate;
+        end;
+      end;
+    end;
+    //汇总动态燃料
+    for I := 0 to lstFuelAmount.Count - 1 do
+    begin
+      pFuel := PGLJAmount(lstFuelAmount[I]);
+      GLJRec := LocateGLJ(pFuel^.ID);
+      GLJRec.Amount.AsCurrency := GLJRec.Amount.AsCurrency + ScRoundTo(pFuel^.Amount, -iDigit);
+      GLJRec.TenderAmount.AsCurrency := GLJRec.TenderAmount.AsCurrency + ScRoundTo(pFuel^.TenderAmount, -iDigit);
+
+      Dispose(lstFuelAmount[I]);
     end;
   finally
+    lstFuel.Free;
+    lstFuelAmount.Free;
     GLJList.Free;
     MachineList.Free;
     Map.Free;
   end;
-
-  for I := Low(MachineRelaGLKeys) to High(MachineRelaGLKeys) do
-  begin
-    GLJRec := LocateGLJ(MachineRelaGLKeys[I]);
-    if GLJRec <> nil then
-    begin
-      GLJRec.BeginUpdate;
-      try
-        GLJRec.Amount.AsCurrency := GLJRec.Amount.AsCurrency + ScRoundTo(RelaGL[I], -iDigit);
-        GLJRec.TenderAmount.AsCurrency := GLJRec.TenderAmount.AsCurrency + ScRoundTo(RelaTenderGL[I], -iDigit);
-      finally
-        GLJRec.EndUpdate;
-      end;
-    end;
-  end;
 end;
 
 type
@@ -1295,9 +1376,11 @@ begin
       TScProject(FProject).Properties.HasMergedGLJ := True;
       TScProjBaseData(TScProject(FProject).ProjData).IsLocalFile := True;
     end;
+    TScProject(FProject).RationLibs.AddResponder(Self);
   end
   else
   begin
+    TScProject(FProject).RationLibs.RemoveResponder(Self);
     DataActive := False;
     sdvProjectGLJ.Close;
     sdsProjectGLJ.Close;
@@ -4670,7 +4753,7 @@ begin
     else if SameText(ATableName, SProperty) then
     begin
       if SameText(AFieldName, SFeeTaxFile) then
-        FMachineData.SyncData(ATableName, AFieldName, nil, AKey3)
+        FMachineData.SyncData(ATableName, AFieldName, nil, AKey3, '')
       else if SameText(AFieldName, SMachineBBFeeRate) then
       begin
         with TScProjBaseData(TScProject(FProject).ProjData) do
@@ -4686,11 +4769,15 @@ begin
     end
     else if SameText(ATableName, SMachinePrice) then
     begin
-      FMachineData.SyncData(ATableName, AFieldName, ARecord, AKey3);
+      FMachineData.SyncData(ATableName, AFieldName, ARecord, AKey3, '');
+    end
+    else if SameText(ATableName, SMachineDetail) then
+    begin
+      FMachineData.SyncData(ATableName, AFieldName, ARecord, AKey3, AKey4);
     end
     else if SameText(ATableName, SMachineLabours) then
     begin
-      FMachineData.SyncData(ATableName, AFieldName, ARecord, '');
+      FMachineData.SyncData(ATableName, AFieldName, ARecord, '', '');
     end
     else if SameText(ATableName, SMaterialPrice)
       or SameText(ATableName, SMaterialTransPrice)
@@ -5208,7 +5295,7 @@ begin
     Rec := TScProjectGLJRecord(AValue.Owner);
     if AValue.AsCurrency <> ScVarToCurrency(NewValue) then
     begin
-      if ArrayIndexOf(CombineGLJKeys(Rec), MachineRelaGLKeys) >= 0 then
+      if FMachineData.IsMachineRelaGL(CombineGLJKeys(Rec)) then
         FMachineRelaPriceChanged := True;
       // 发电机单价变化,要在这里触发电价重新计算
       if ArrayIndexOf(Rec.Code.AsString, ElectMachineCodes) >= 0 then
@@ -5217,4 +5304,33 @@ begin
   end;
 end;
 
+// 新增《广东省干线公路养护工程预算定额(2025)》定额库,检查液化气价格
+procedure TProjectGLJ.SCMAddRationLib(var Message: TMessage);
+var
+  iLibID: Integer;
+  RationLib: TScProjectRationLib;
+  strLibName: string;
+  ProjectGLJRec: TScProjectGLJRecord;
+  rlGLJRec: TrlGLJListRecord;
+begin
+  iLibID := Message.WParam;
+  RationLib := TScProject(FProject).RationLibs.FindLibByID(iLibID);
+  if RationLib <> nil then
+  begin
+    strLibName := RationLib.LibName;
+    if Pos('广东省干线公路养护工程预算定额(2025)', strLibName) > 0 then
+    begin
+      AddMachineRelaGL(0);
+      ProjectGLJRec := LocateGLJ(SYHQKeys);
+      rlGLJRec := RationLib.LocateGLJ(SYHQKeys);
+      // 此定额库液化气改为7.62元
+      if (ProjectGLJRec <> nil) and (rlGLJRec <> nil) then
+      begin
+        ProjectGLJRec.BasePrice.AsCurrency := rlGLJRec.BasePrice.AsCurrency;
+        ProjectGLJRec.BudgetPrice.AsCurrency := rlGLJRec.BasePrice.AsCurrency;
+      end;
+    end;
+  end;
+end;
+
 end.

+ 2 - 0
MainModule/Model/ScUpdateDataBase.pas

@@ -218,6 +218,7 @@ begin
       Updater.AddTableDef(SRationCalcList, @tdRationCalcList, Length(tdRationCalcList), False, False);
       Updater.AddTableDef(SGLJList, @tdGLJList, Length(tdGLJList), False, True);
       Updater.AddTableDef(SMachinePrice, @tdMachinePrice, Length(tdMachinePrice), False, True);
+      Updater.AddTableDef(SMachineDetail, @tdMachineDetail, Length(tdMachineDetail), False, True);
       Updater.AddTableDef(SMaterialPrice, @tdMaterialPrice, Length(tdMaterialPrice), False, True);
       Updater.AddTableDef(SMaterialTransPrice, @tdMaterialTransPrice, Length(tdMaterialTransPrice), False, False);
       Updater.AddTableDef(SMaterialOrgPrice, @tdMaterialOrgPrice, Length(tdMaterialOrgPrice), False, False);
@@ -374,6 +375,7 @@ begin
     begin
       Updater.AddTableDef(SUGLJList, @tdUGLJList, Length(tdUGLJList), False, True);
       Updater.AddTableDef(SUMachinePrice, @tdUMachinePrice, Length(tdUMachinePrice), False, True);
+      Updater.AddTableDef(SUMachineDetail, @tdUMachineDetail, Length(tdUMachineDetail), False, True);
       Updater.AddTableDef(SMachineLabours, @tdMachineLabours, Length(tdMachineLabours), False, False);
       Updater.AddTableDef(SUMaterialPrice, @tdUMaterialPrice, Length(tdUMaterialPrice), False, True);
       Updater.AddTableDef(SUMaterialTransPrice, @tdUMaterialTransPrice, Length(tdUMaterialTransPrice), False, False);

+ 2 - 1
MainModule/UI/ScGLJGatherView.dfm

@@ -32,7 +32,7 @@ object ScFrmGLJGatherView: TScFrmGLJGatherView
       Top = 22
       Width = 1195
       Height = 234
-      ActivePage = tsMaterialPrice
+      ActivePage = tsMachinePrice
       Align = alClient
       MultiLine = True
       TabOrder = 0
@@ -476,6 +476,7 @@ object ScFrmGLJGatherView: TScFrmGLJGatherView
           FrozenCol = 0
           FrozenRow = 0
           OnGetCellText = zgMachinePriceGetCellText
+          OnSetCellText = zgMachinePriceSetCellText
           OnCellTextChanging = zgMachinePriceCellTextChanging
           OnGetCellEditor = zgMachinePriceGetCellEditor
           OnEditorLoadCell = zgMachinePriceEditorLoadCell

+ 172 - 6
MainModule/UI/ScGLJGatherView.pas

@@ -267,6 +267,8 @@ type
       const ACoord: TPoint; var NewValue: String; var Accept: Boolean);
     procedure zgMachineLaboursCellTextChanging(Sender: TObject;
       const ACoord: TPoint; var NewValue: String; var Accept: Boolean);
+    procedure zgMachinePriceSetCellText(Sender: TObject;
+      const ACoord: TPoint; var Value: String; DisplayText: Boolean);
   private
     { Private declarations }
     FShowBBFeeHint: Boolean;
@@ -314,6 +316,8 @@ type
     procedure DoOnGLJScrolled(Sender: TObject);
     procedure MtCalcCopy(Sender: TObject; ABounds: TRect; var Allow: Boolean);
     procedure MtCalcPaste(Sender: TObject; ABounds: TRect; var Allow: Boolean);
+    procedure RefreshMachineView;
+    procedure DoOnMachineDetailColumnsChanged(Sender: TObject);
   public
     { Public declarations }
     constructor Create(AOwner: TComponent); override;
@@ -433,6 +437,8 @@ begin
   FProjectGLJ.MachineData.FeeTaxDM.OnFileChanged := DoOnFeeTaxFileChanged;
 
   FProjectGLJ.OnGLJScrolled := DoOnGLJScrolled;
+
+  FProjectGLJ.MachineData.OnMachineDetailColumnChanged := DoOnMachineDetailColumnsChanged;
 end;
 
 procedure TScFrmGLJGatherView.ShowDetail(AViewType: TGLJDetailType;
@@ -468,7 +474,17 @@ begin
         else if pcGLJGather.ActivePage = tsMaterialPrice then
           AViewType := gdtMaterialPriceCalc
         else if pcGLJGather.ActivePage = tsMachinePrice then
+        begin
           AViewType := gdtMachinePriceCalc;
+          if FProjectGLJ <> nil then
+          begin
+            GLJTypeView.Zero;
+            FProjectGLJ.FilterProjGLJ(Format('Type = %d', [GLJ_Machine]), '', False);
+            RefreshMachineView;
+          end;
+          if Active then
+            zgMachinePrice.SetFocus;
+        end;
       end;
       gdtGLJAll:
       begin
@@ -504,6 +520,7 @@ begin
         begin
           GLJTypeView.Zero;
           FProjectGLJ.FilterProjGLJ(Format('Type = %d', [GLJ_Machine]), '', True);
+          RefreshMachineView;
         end;
         if Active then
           zgMachinePrice.SetFocus;
@@ -1262,7 +1279,7 @@ begin
       else if Rec.Types.AsInteger = GLJ_Machine then
       begin
         // 有机械台班,不允许修改单价
-        Accept := not FProjectGLJ.MachineData.HasDetail(Rec.ID.AsInteger);
+        Accept := not FProjectGLJ.MachineData.HasMachine(Rec.ID.AsInteger);
         if not Accept then
           MessageHint(0, '当前机械有费用组成,请进入左下方“机械单价”窗口清空该机械费用组成数据,即可直接修改机械预算单价。');
       end;
@@ -2469,15 +2486,51 @@ var
   iIdx: Integer;
   Rec: TsdDataRecord;
   Col: TsdGridColumn;
+  fQuantity: Double;
 begin
   if sgdMachinePrice.FindColumn(ACoord.X, Col) then
-    if SameText(Col.FieldName, SRGName) then
+  begin
+    iIdx := ACoord.Y - zgMachinePrice.FixedRowCount;
+    Rec := sgdMachinePrice.DataView[iIdx];
+    if Rec <> nil then
+    begin
+      if SameText(Col.FieldName, SRGName) then
+        Value := ProjectGLJ.MachineData.LookupMachineLabourName(Rec.ValueByName(SRGType).AsInteger)
+      // 动力燃料,包括Fuel开头的
+      else if (ArrayIndexOf(Col.FieldName, MachineFuelFields) >= 0) or (Pos(SFuel, Col.FieldName) = 1) then
+      begin
+        fQuantity := FProjectGLJ.MachineData.GetFuelQuantity(Rec.ValueByName(SID).AsInteger, Col.Title.Captions[Col.Title.CaptionCount - 1]);
+        if fQuantity <> 0 then
+          Value := FloatToStr(fQuantity);
+        if Value = '' then
+          Value := '0';  
+      end;
+    end;
+  end;
+end;
+
+procedure TScFrmGLJGatherView.zgMachinePriceSetCellText(Sender: TObject;
+  const ACoord: TPoint; var Value: String; DisplayText: Boolean);
+var
+  iIdx: Integer;
+  Rec: TsdDataRecord;
+  Col: TsdGridColumn;
+  fQuantity: Double;
+begin
+  if sgdMachinePrice.FindColumn(ACoord.X, Col) then
+  begin
+    iIdx := ACoord.Y - zgMachinePrice.FixedRowCount;
+    Rec := sgdMachinePrice.DataView[iIdx];
+    if Rec <> nil then
     begin
-      iIdx := ACoord.Y - zgMachinePrice.FixedRowCount;
-      Rec := sgdMachinePrice.DataView[iIdx];
-      if Rec <> nil then
-        Value := ProjectGLJ.MachineData.LookupMachineLabourName(Rec.ValueByName(SRGType).AsInteger);
+      // 动力燃料,包括Fuel开头的
+      if (ArrayIndexOf(Col.FieldName, MachineFuelFields) >= 0) or (Pos(SFuel, Col.FieldName) = 1) then
+      begin
+        if TryStrToFloat(Value, fQuantity) then
+          FProjectGLJ.MachineData.SetFuelQuantity(Rec.ValueByName(SID).AsInteger, Col.Title.Captions[Col.Title.CaptionCount - 1], fQuantity);
+      end;
     end;
+  end;
 end;
 
 procedure TScFrmGLJGatherView.actnNeiMengTransPriceUpdate(Sender: TObject);
@@ -2635,4 +2688,117 @@ begin
     FProject.OperationManager.SnapShoot(Format('%s原价定额%s', [AOperation, zgOrgRations.Cells[1, zgOrgRations.CurRow].Text]));
 end;
 
+procedure TScFrmGLJGatherView.RefreshMachineView;
+var
+  bMeiQ, bYHQ, bTRQ: Boolean;
+
+  procedure CheckQColVisible;
+  var
+    I: Integer;
+    Rec: TsdDataRecord;
+  begin
+    bMeiQ := False;
+    bYHQ := False;
+    bTRQ := False;
+    for I := 0 to FProjectGLJ.MachineData.sdvMachinePrice.RecordCount - 1 do
+    begin
+      Rec := FProjectGLJ.MachineData.sdvMachinePrice[I];
+      if Rec.ValueByName(SMeiQ).AsFloat <> 0 then
+        bMeiQ := True;
+      if Rec.ValueByName(SYHQ).AsFloat <> 0 then
+        bYHQ := True;
+      if Rec.ValueByName(STRQ).AsFloat <> 0 then
+        bTRQ := True;
+      if bMeiQ and bYHQ and bTRQ then
+        Break;
+    end;
+  end;
+
+var
+  I, iFuelColCount, iLastFuelCol: Integer;
+  slstCol: TStringList;
+  Col: TsdGridColumn;
+  strField: string;
+begin
+  slstCol := TStringList.Create;
+  try
+    // 检查三气列
+    CheckQColVisible;
+    // 默认动力燃料列数
+    iFuelColCount := 10;
+    // 煤气
+    Col := sgdMachinePrice.Column(SMeiQ);
+    Col.Visible := bMeiQ and (FProjectGLJ.MachineData.FuelColumns.IndexOfName(SNMeiQCode) >= 0);
+    if not Col.Visible then
+      Dec(iFuelColCount);
+    // 液化气
+    Col := sgdMachinePrice.Column(SYHQ);
+    Col.Visible := bYHQ and (FProjectGLJ.MachineData.FuelColumns.IndexOfName(SNYHQCode) >= 0);
+    if not Col.Visible then
+      Dec(iFuelColCount);
+    // 天然气
+    Col := sgdMachinePrice.Column(STRQ);
+    Col.Visible := bTRQ and (FProjectGLJ.MachineData.FuelColumns.IndexOfName(SNTRQCode) >= 0);
+    if not Col.Visible then
+      Dec(iFuelColCount);
+
+    // 天然气列为最后一列动力燃料
+    iLastFuelCol := 19;
+    // 其它燃料
+    for I := 0 to FProjectGLJ.MachineData.FuelColumns.Count - 1 do
+    begin
+      // 先查找是否存在Fuel1...
+      strField := FProjectGLJ.MachineData.FuelColumns.ValueFromIndex[I];
+      if Pos(SFuel, strField) > 0 then
+      begin
+        Col := sgdMachinePrice. Column(strField);
+        // 没有添加
+        if Col = nil then
+          Col := TsdGridColumn(sgdMachinePrice.Columns.Insert(iLastFuelCol + 1));
+        Col.FieldName := strField;
+        Col.Title.Caption := Format('||%s', [FProjectGLJ.MachineData.FuelColumns.Names[I]]);
+        Col.Width := 50;
+        Col.Alignment := taRightJustify;
+        Inc(iLastFuelCol);
+      end;
+    end;
+    // 检查有没有多余DLRL列
+    repeat
+      Inc(iLastFuelCol);
+      Col := sgdMachinePrice.Columns[iLastFuelCol];
+      if (Col <> nil) and (Pos(SFuel, Col.FieldName) > 0) then
+      begin
+        sgdMachinePrice.Columns.Delete(Col.Index)
+      end
+      else
+        Break;
+    until True;
+
+    // 可变费用/机械工列
+    Col := sgdMachinePrice.Column(SRG);
+    Col.Title.CaptionAcrossCols := Format('%d|1', [5 + iFuelColCount]);
+    // 重油列
+    Col := sgdMachinePrice.Column(SZY);
+    Col.Title.CaptionAcrossCols := Format('1|%d|1', [2 + iFuelColCount]);
+
+    // 最后再处理合并单元格
+    // 折旧费、检修费、维护费、安拆辅助费、合计、机械工
+    for I := 4 to 9 do
+      zgMachinePrice.Merge(Rect(I, 1, I + 1, 3));
+    // 车船税
+    zgMachinePrice.Merge(Rect(12 + iFuelColCount, 1, 13 + iFuelColCount, 3));
+    // 合计
+    zgMachinePrice.Merge(Rect(13 + iFuelColCount, 1, 14 + iFuelColCount, 3));
+
+  finally
+    slstCol.Free;
+  end;
+end;
+
+procedure TScFrmGLJGatherView.DoOnMachineDetailColumnsChanged(
+  Sender: TObject);
+begin
+  RefreshMachineView;
+end;
+
 end.

+ 9 - 9
MainUI/Forms/ScMainFrm.dfm

@@ -194,23 +194,23 @@ object ScMainForm: TScMainForm
     Left = 0
     Top = 0
     Width = 954
-    Height = 50
+    Height = 49
     Align = dalTop
     BarManager = xbmMain
   end
   object xbdLeft: TdxBarDockControl
     Left = 0
-    Top = 74
+    Top = 73
     Width = 3
-    Height = 527
+    Height = 529
     Align = dalLeft
     BarManager = xbmMain
   end
   object xbdRight: TdxBarDockControl
     Left = 951
-    Top = 74
+    Top = 73
     Width = 3
-    Height = 527
+    Height = 529
     Align = dalRight
     BarManager = xbmMain
   end
@@ -224,7 +224,7 @@ object ScMainForm: TScMainForm
   end
   object pnlTabs: TPanel
     Left = 0
-    Top = 50
+    Top = 49
     Width = 954
     Height = 24
     Align = alTop
@@ -613,7 +613,7 @@ object ScMainForm: TScMainForm
     AutoDockColor = False
     Font.Charset = DEFAULT_CHARSET
     Font.Color = clWindowText
-    Font.Height = -13
+    Font.Height = -12
     Font.Name = #23435#20307
     Font.Style = []
     Bars = <
@@ -685,7 +685,7 @@ object ScMainForm: TScMainForm
         DockControl = xbdTop
         DockedDockControl = xbdTop
         DockedLeft = 0
-        DockedTop = 23
+        DockedTop = 22
         FloatLeft = 232
         FloatTop = 274
         FloatClientWidth = 23
@@ -1089,7 +1089,7 @@ object ScMainForm: TScMainForm
       0
       0
       0
-      20)
+      19)
     object xsCurOperation: TdxBarStatic
       Caption = #23601#32490
       Category = 18

TEMPAT SAMPAH
MainUI/Forms/ScProjFrm.dfm


+ 37 - 4
SideModule/Ration/ScProjectRationLibsUnit.pas

@@ -28,6 +28,8 @@ type
     FOwnerList: TScProjectRationLibs;
     FListener: TScMessagelisteners;
     FSelected: Boolean;
+    // 是否新添加的定额库
+    FNew: Boolean;
     procedure SetLib(ALib: TScRationLib);
     function GetLib: TScRationLib;
     function GetProviderID: Integer;
@@ -144,6 +146,10 @@ type
     procedure AddResponder(AResponder: TObject);
     procedure RemoveResponder(AResponder: TObject);
     function RationLibNames: string;
+    // 根据ProjectRationLibs中的ID查找Lib原始ID
+    function LibIDByID(AID: Integer): Integer;
+    // 根据Lib原始ID查找ProjectRationLibs中的ID
+    function IDByLibID(ALibID: Integer): Integer;
     // ID 是持久化的ID,不一定是连续的
     property Libs[ID: Integer]: TScProjectRationLib read GetLibs; default;
     property LibID[Index: Integer]: Integer read GetLibID;
@@ -156,7 +162,8 @@ type
 implementation
 
 uses
-  ScProject, Variants, ScProjBaseDM, ScConfig, ScRations, Forms, ScProgressFrm;
+  ScProject, Variants, ScProjBaseDM, ScConfig, ScRations, Forms, ScProgressFrm,
+  Math;
 
 {$R *.dfm}
 
@@ -500,6 +507,7 @@ begin
   FActive := False;
   FActiveLib := False;
   FSelected := False;
+  FNew := False;
 end;
 
 procedure TScProjectRationLib.DataModuleDestroy(Sender: TObject);
@@ -785,7 +793,9 @@ begin
   AddIDMap(Lib.ID, Lib.ID);
   FLibList.Add(Lib);
   Result := Lib.ID;
-  FListener.Perform(SCM_ActiveRationLibChanged, FActiveLibID, 1);
+  if AIsActive then
+    FListener.Perform(SCM_ActiveRationLibChanged, FActiveLibID, 1);
+  Lib.FNew := True;
 end;
 
 procedure TScProjectRationLibs.AddLibs(AFiles: TStrings;
@@ -959,7 +969,7 @@ begin
     end;
     FDSFile.Next;
   end;
-  FListener.Perform(SCM_ActiveRationLibChanged, FActiveLibID, 1);
+  //FListener.Perform(SCM_ActiveRationLibChanged, FActiveLibID, 1);
 end;
 
 {
@@ -1026,7 +1036,9 @@ begin
     Lib.Open;
     //TScProject(FProject).CheckRelaFile(Lib.FileName);
     TScProject(FProject).SyncRelaFiles(FileType_RationLib);
-    FListener.Perform(SCM_ActiveRationLibChanged, FActiveLibID, 1);
+    //FListener.Perform(SCM_ActiveRationLibChanged, FActiveLibID, 1);
+    if Lib.FNew then
+      FListener.Perform(SCM_AddRationLib, Lib.ID, 0);
   end;
 end;
 
@@ -1063,6 +1075,7 @@ begin
       end;
     end;
   end;
+  FListener.Perform(SCM_ActiveRationLibChanged, FActiveLibID, 1);
 end;
 
 procedure TScProjectRationLibs.Remove(AID: Integer);
@@ -1477,4 +1490,24 @@ begin
   end;
 end;
 
+function TScProjectRationLibs.LibIDByID(AID: Integer): Integer;
+begin
+  Result := MapID(AID);
+end;
+
+function TScProjectRationLibs.IDByLibID(ALibID: Integer): Integer;
+var
+  I: Integer;
+begin
+  Result := -1;
+  for I := 0 to FLibList.Count - 1 do
+  begin
+    if ALibID = TScProjectRationLib(FLibList[I]).Lib.ID then
+    begin
+      Result := TScProjectRationLib(FLibList[I]).ID;
+      Break;
+    end;
+  end;
+end;
+
 end.

+ 144 - 1
SideModule/Ration/ScRationLibsUnit.dfm

@@ -5,7 +5,7 @@ object ScRationLib: TScRationLib
   Left = 316
   Top = 141
   Height = 314
-  Width = 563
+  Width = 742
   object atLibInfo: TADOTable
     TableName = 'LibInfo'
     Left = 32
@@ -50,6 +50,7 @@ object ScRationLib: TScRationLib
     Active = False
     Filtered = False
     Provider = sapGLJ
+    UseSavePoint = False
     AfterOpen = sdsGLJAfterOpen
     OnGetRecordClass = sdsGLJGetRecordClass
     Left = 32
@@ -115,6 +116,7 @@ object ScRationLib: TScRationLib
     Active = False
     Filtered = False
     Provider = sapCoe
+    UseSavePoint = False
     OnGetRecordClass = sdsCoeGetRecordClass
     Left = 408
     Top = 168
@@ -254,4 +256,145 @@ object ScRationLib: TScRationLib
       6153697A6503FF000549734B6579080F4E65656450726F636573734E616D6509
       09507265636973696F6E02000453697A6502000000}
   end
+  object sapMachineDetail: TsdADOProvider
+    TableName = 'MachineDetail'
+    Left = 592
+    Top = 112
+  end
+  object sdsMachineDetail: TsdDataSet
+    Active = False
+    Filtered = False
+    Provider = sapMachineDetail
+    UseSavePoint = False
+    Left = 592
+    Top = 168
+    FieldListData = {
+      0101044E616D6506024944094669656C644E616D650602494408446174615479
+      70650203084461746153697A6502040549734B6579080F4E65656450726F6365
+      73734E616D650909507265636973696F6E02000453697A6502000001044E616D
+      650604436F6465094669656C644E616D650604436F6465084461746154797065
+      0218084461746153697A6503FF000549734B6579080F4E65656450726F636573
+      734E616D650909507265636973696F6E02000453697A6502000001044E616D65
+      06044E616D65094669656C644E616D6506044E616D6508446174615479706502
+      18084461746153697A6503FF000549734B6579080F4E65656450726F63657373
+      4E616D650909507265636973696F6E02000453697A6502000001044E616D6506
+      055370656373094669656C644E616D6506055370656373084461746154797065
+      0218084461746153697A6503FF000549734B6579080F4E65656450726F636573
+      734E616D650909507265636973696F6E02000453697A6502000001044E616D65
+      0604556E6974094669656C644E616D650604556E697408446174615479706502
+      18084461746153697A6503FF000549734B6579080F4E65656450726F63657373
+      4E616D650909507265636973696F6E02000453697A6502000001044E616D6506
+      074F776E65724944094669656C644E616D6506074F776E657249440844617461
+      547970650203084461746153697A6502040549734B6579080F4E65656450726F
+      636573734E616D650909507265636973696F6E02000453697A6502000001044E
+      616D6506094F776E6572436F6465094669656C644E616D6506094F776E657243
+      6F64650844617461547970650218084461746153697A6503FF000549734B6579
+      080F4E65656450726F636573734E616D650909507265636973696F6E02000453
+      697A6502000001044E616D6506094F776E65724E616D65094669656C644E616D
+      6506094F776E65724E616D650844617461547970650218084461746153697A65
+      03FF000549734B6579080F4E65656450726F636573734E616D65090950726563
+      6973696F6E02000453697A6502000001044E616D65060A4F776E657253706563
+      73094669656C644E616D65060A4F776E65725370656373084461746154797065
+      0218084461746153697A6503FF000549734B6579080F4E65656450726F636573
+      734E616D650909507265636973696F6E02000453697A6502000001044E616D65
+      06094F776E6572556E6974094669656C644E616D6506094F776E6572556E6974
+      0844617461547970650218084461746153697A6503FF000549734B6579080F4E
+      65656450726F636573734E616D650909507265636973696F6E02000453697A65
+      02000001044E616D650609426173655072696365094669656C644E616D650609
+      4261736550726963650844617461547970650207084461746153697A65020805
+      49734B6579080F4E65656450726F636573734E616D650909507265636973696F
+      6E02000453697A6502000001044E616D6506085175616E74697479094669656C
+      644E616D6506085175616E746974790844617461547970650206084461746153
+      697A6502080549734B6579080F4E65656450726F636573734E616D6509095072
+      65636973696F6E02000453697A6502000000}
+  end
+  object sapMachinePrice: TsdADOProvider
+    TableName = 'MachinePrice'
+    UpdateByKey = False
+    Left = 504
+    Top = 112
+  end
+  object sdsMachinePrice: TsdDataSet
+    Active = False
+    Filtered = False
+    Provider = sapMachinePrice
+    UseSavePoint = False
+    Left = 504
+    Top = 168
+    FieldListData = {
+      0101044E616D650604436F6465094669656C644E616D650604436F6465084461
+      7461547970650218084461746153697A6503FF000549734B6579080F4E656564
+      50726F636573734E616D650809507265636973696F6E02000453697A65020000
+      01044E616D6506044E616D65094669656C644E616D6506044E616D6508446174
+      61547970650218084461746153697A6503FF000549734B6579080F4E65656450
+      726F636573734E616D650809507265636973696F6E02000453697A6502000001
+      044E616D6506055370656373094669656C644E616D6506055370656373084461
+      7461547970650218084461746153697A6503FF000549734B6579080F4E656564
+      50726F636573734E616D650809507265636973696F6E02000453697A65020000
+      01044E616D650604556E6974094669656C644E616D650604556E697408446174
+      61547970650218084461746153697A6503FF000549734B6579080F4E65656450
+      726F636573734E616D650809507265636973696F6E02000453697A6502000001
+      044E616D6506025A4A094669656C644E616D6506025A4A084461746154797065
+      0208084461746153697A6502080549734B6579080F4E65656450726F63657373
+      4E616D650809507265636973696F6E02130453697A6502040001044E616D6506
+      0344584C094669656C644E616D65060344584C08446174615479706502080844
+      61746153697A6502080549734B6579080F4E65656450726F636573734E616D65
+      0809507265636973696F6E02130453697A6502040001044E616D6506044A4358
+      4C094669656C644E616D6506044A43584C084461746154797065020808446174
+      6153697A6502080549734B6579080F4E65656450726F636573734E616D650809
+      507265636973696F6E02130453697A6502040001044E616D650604415A465A09
+      4669656C644E616D650604415A465A0844617461547970650208084461746153
+      697A6502080549734B6579080F4E65656450726F636573734E616D6508095072
+      65636973696F6E02130453697A6502040001044E616D6506025247094669656C
+      644E616D65060252470844617461547970650208084461746153697A65020805
+      49734B6579080F4E65656450726F636573734E616D650809507265636973696F
+      6E02130453697A6502040001044E616D650604444C524C094669656C644E616D
+      650604444C524C0844617461547970650208084461746153697A650208054973
+      4B6579080F4E65656450726F636573734E616D650809507265636973696F6E02
+      130453697A6502040001044E616D6506025A59094669656C644E616D6506025A
+      590844617461547970650208084461746153697A6502080549734B6579080F4E
+      65656450726F636573734E616D650809507265636973696F6E02130453697A65
+      02040001044E616D6506025159094669656C644E616D65060251590844617461
+      547970650208084461746153697A6502080549734B6579080F4E65656450726F
+      636573734E616D650809507265636973696F6E02130453697A6502040001044E
+      616D6506024359094669656C644E616D65060243590844617461547970650208
+      084461746153697A6502080549734B6579080F4E65656450726F636573734E61
+      6D650809507265636973696F6E02130453697A6502040001044E616D6506034D
+      6569094669656C644E616D6506034D6569084461746154797065020808446174
+      6153697A6502080549734B6579080F4E65656450726F636573734E616D650809
+      507265636973696F6E02130453697A6502040001044E616D6506044469616E09
+      4669656C644E616D6506044469616E0844617461547970650208084461746153
+      697A6502080549734B6579080F4E65656450726F636573734E616D6508095072
+      65636973696F6E02130453697A6502040001044E616D65060453687569094669
+      656C644E616D650604536875690844617461547970650208084461746153697A
+      6502080549734B6579080F4E65656450726F636573734E616D65080950726563
+      6973696F6E02130453697A6502040001044E616D6506024D43094669656C644E
+      616D6506024D430844617461547970650208084461746153697A650208054973
+      4B6579080F4E65656450726F636573734E616D650809507265636973696F6E02
+      130453697A6502040001044E616D6506044D656951094669656C644E616D6506
+      044D6569510844617461547970650208084461746153697A6502080549734B65
+      79080F4E65656450726F636573734E616D650909507265636973696F6E020004
+      53697A6502000001044E616D650603594851094669656C644E616D6506035948
+      510844617461547970650208084461746153697A6502080549734B6579080F4E
+      65656450726F636573734E616D650909507265636973696F6E02000453697A65
+      02000001044E616D650603545251094669656C644E616D650603545251084461
+      7461547970650208084461746153697A6502080549734B6579080F4E65656450
+      726F636573734E616D650909507265636973696F6E02000453697A6502000001
+      044E616D650604594C4343094669656C644E616D650604594C43430844617461
+      547970650208084461746153697A6502080549734B6579080F4E65656450726F
+      636573734E616D650809507265636973696F6E02130453697A6502040001044E
+      616D650609426173655072696365094669656C644E616D650609426173655072
+      6963650844617461547970650208084461746153697A6502080549734B657908
+      0F4E65656450726F636573734E616D650809507265636973696F6E0213045369
+      7A6502040001044E616D6506054242466565094669656C644E616D6506054242
+      4665650844617461547970650208084461746153697A6502080549734B657908
+      0F4E65656450726F636573734E616D650809507265636973696F6E0213045369
+      7A6502040001044E616D6506054B42466565094669656C644E616D6506054B42
+      4665650844617461547970650208084461746153697A6502080549734B657908
+      0F4E65656450726F636573734E616D650809507265636973696F6E0213045369
+      7A6502040001044E616D650606524754797065094669656C644E616D65060652
+      47547970650844617461547970650203084461746153697A6502040549734B65
+      79080F4E65656450726F636573734E616D650809507265636973696F6E020004
+      53697A6502000000}
+  end
 end

+ 28 - 4
SideModule/Ration/ScRationLibsUnit.pas

@@ -1,3 +1,8 @@
+{
+  Zhangyin 2026-05-28 因为不同省份存在不同编号不同单位的液化气,
+    在补充定额库中新增表MachineMachine,保存机械台班
+    在补充定额库中新增表MachineDetail,保存动力燃料明细
+}
 unit ScRationLibsUnit;
 
 interface
@@ -174,6 +179,10 @@ type
     sdsGLJ: TsdDataSet;
     sapCoe: TsdADOProvider;
     sdsCoe: TsdDataSet;
+    sapMachineDetail: TsdADOProvider;
+    sdsMachineDetail: TsdDataSet;
+    sapMachinePrice: TsdADOProvider;
+    sdsMachinePrice: TsdDataSet;
     procedure DataModuleCreate(Sender: TObject);
     procedure DataModuleDestroy(Sender: TObject);
     procedure sdsGLJGetRecordClass(var ARecordClass: TsdRecordClass);
@@ -563,13 +572,28 @@ end;
 
 procedure TScRationLib.SetDataSetActive(Value: Boolean);
 var
-  I: Integer;
+  slstTables: TStringList;
 begin
   atLibInfo.Active := Value;
-  for I := 0 to ComponentCount - 1 do
+  sdsGLJ.Active := Value;
+  sdsCoe.Active := Value;
+  if Active then
+  begin
+    slstTables := TStringList.Create;
+    try
+      Connection.GetTableNames(slstTables);
+      if slstTables.IndexOf('MachinePrice') >= 0 then
+        sdsMachinePrice.Open;
+      if slstTables.IndexOf('MachineDetail') >= 0 then
+        sdsMachineDetail.Open;
+    finally
+      slstTables.Free;
+    end;
+  end
+  else
   begin
-    if Components[I] is TsdDataSet then
-      TsdDataSet(Components[I]).Active := Value;
+    sdsMachinePrice.Close;
+    sdsMachineDetail.Close;
   end;
 end;
 

+ 56 - 1
SideModule/UnitPrice/ScUnitPriceLibsUnit.dfm

@@ -5,7 +5,7 @@ object ScUnitPriceLib: TScUnitPriceLib
   Left = 318
   Top = 210
   Height = 530
-  Width = 565
+  Width = 881
   object sapGLJTree: TsdADOProvider
     TableName = 'GLJTypeTree'
     Left = 40
@@ -754,4 +754,59 @@ object ScUnitPriceLib: TScUnitPriceLib
       547970650206084461746153697A6502080549734B6579080F4E65656450726F
       636573734E616D650809507265636973696F6E02000453697A6502000000}
   end
+  object sapMachineDetail: TsdADOProvider
+    TableName = 'MachineDetail'
+    Left = 592
+    Top = 16
+  end
+  object sdsMachineDetail: TsdDataSet
+    Active = False
+    Filtered = False
+    Provider = sapMachineDetail
+    UseSavePoint = False
+    Left = 592
+    Top = 80
+    FieldListData = {
+      0101044E616D6506024944094669656C644E616D650602494408446174615479
+      70650203084461746153697A6502040549734B6579080F4E65656450726F6365
+      73734E616D650909507265636973696F6E02000453697A6502000001044E616D
+      650604436F6465094669656C644E616D650604436F6465084461746154797065
+      0218084461746153697A6503FF000549734B6579080F4E65656450726F636573
+      734E616D650909507265636973696F6E02000453697A6502000001044E616D65
+      06044E616D65094669656C644E616D6506044E616D6508446174615479706502
+      18084461746153697A6503FF000549734B6579080F4E65656450726F63657373
+      4E616D650909507265636973696F6E02000453697A6502000001044E616D6506
+      055370656373094669656C644E616D6506055370656373084461746154797065
+      0218084461746153697A6503FF000549734B6579080F4E65656450726F636573
+      734E616D650909507265636973696F6E02000453697A6502000001044E616D65
+      0604556E6974094669656C644E616D650604556E697408446174615479706502
+      18084461746153697A6503FF000549734B6579080F4E65656450726F63657373
+      4E616D650909507265636973696F6E02000453697A6502000001044E616D6506
+      074F776E65724944094669656C644E616D6506074F776E657249440844617461
+      547970650203084461746153697A6502040549734B6579080F4E65656450726F
+      636573734E616D650909507265636973696F6E02000453697A6502000001044E
+      616D6506094F776E6572436F6465094669656C644E616D6506094F776E657243
+      6F64650844617461547970650218084461746153697A6503FF000549734B6579
+      080F4E65656450726F636573734E616D650909507265636973696F6E02000453
+      697A6502000001044E616D6506094F776E65724E616D65094669656C644E616D
+      6506094F776E65724E616D650844617461547970650218084461746153697A65
+      03FF000549734B6579080F4E65656450726F636573734E616D65090950726563
+      6973696F6E02000453697A6502000001044E616D65060A4F776E657253706563
+      73094669656C644E616D65060A4F776E65725370656373084461746154797065
+      0218084461746153697A6503FF000549734B6579080F4E65656450726F636573
+      734E616D650909507265636973696F6E02000453697A6502000001044E616D65
+      06094F776E6572556E6974094669656C644E616D6506094F776E6572556E6974
+      0844617461547970650218084461746153697A6503FF000549734B6579080F4E
+      65656450726F636573734E616D650909507265636973696F6E02000453697A65
+      02000001044E616D650609426173655072696365094669656C644E616D650609
+      4261736550726963650844617461547970650207084461746153697A65020805
+      49734B6579080F4E65656450726F636573734E616D650909507265636973696F
+      6E02000453697A6502000001044E616D65060B42756467657450726963650946
+      69656C644E616D65060B42756467657450726963650844617461547970650207
+      084461746153697A6502080549734B6579080F4E65656450726F636573734E61
+      6D650809507265636973696F6E02000453697A6502000001044E616D65060851
+      75616E74697479094669656C644E616D6506085175616E746974790844617461
+      547970650206084461746153697A6502080549734B6579080F4E65656450726F
+      636573734E616D650909507265636973696F6E02000453697A6502000000}
+  end
 end

+ 112 - 0
SideModule/UnitPrice/ScUnitPriceLibsUnit.pas

@@ -66,6 +66,8 @@ type
     sdsMtRationLibs: TsdDataSet;
     sapMachineLabours: TsdADOProvider;
     sdsMachineLabours: TsdDataSet;
+    sapMachineDetail: TsdADOProvider;
+    sdsMachineDetail: TsdDataSet;
     procedure DataModuleCreate(Sender: TObject);
     procedure DataModuleDestroy(Sender: TObject);
     procedure sdsGLJListAfterRecordChanged(ARecord: TsdDataRecord);
@@ -101,6 +103,7 @@ type
     function SaveGLJ(ARecord: TsdDataRecord; Sender: TObject; AKind: TUpdateKind): Integer;
     procedure SaveProperty(AFieldName, AValue: string; Sender: TObject; AKind: TUpdateKind);
     procedure SaveMachine(ARecord: TsdDataRecord; AKeys: string; Sender: TObject; AKind: TUpdateKind);
+    procedure SaveMachineDetail(ARecord: TsdDataRecord; AKeys, AOwnerKeys: string; Sender: TObject; AKind: TUpdateKind);
     procedure SaveMachineLabours(ARecord: TsdDataRecord; Sender: TObject; AKind: TUpdateKind);
     procedure SaveMaterial(ARecord: TsdDataRecord; AKeys: string; Sender: TObject; AKind: TUpdateKind);
     procedure SaveMaterialTransPrice(ARecord: TsdDataRecord; AOwnerKeys: string; Sender: TObject; AKind: TUpdateKind);
@@ -129,6 +132,7 @@ type
     function LocateGLJ(AID: Integer): TsdDataRecord; overload;
     function LocateGLJ(AKeys: string): TsdDataRecord; overload;
     function LocateMachine(AKeys: string): TsdDataRecord;
+    function LocateMachineDetail(AKeys: string): TsdDataRecord;
     function LocateMaterial(AKeys: string): TsdDataRecord;
     function IDToKeys(AID: Integer): string;
     function KeysToID(AKeys: string): Integer;
@@ -281,6 +285,7 @@ begin
   sdsGLJTree.Active := Value;
   sdsGLJList.Active := Value;
   sdsMachinePrice.Active := Value;
+  sdsMachineDetail.Active := Value;
   sdsMachineLabours.Active := Value;
   //sdsFeeTax.Active := Value;
   sdsStdFiles.Active := Value;
@@ -494,6 +499,16 @@ begin
     Result := sdsMachinePrice.Locate(SID, GLJRec.ValueByName(SID).AsInteger);
 end;
 
+function TScUnitPriceLib.LocateMachineDetail(AKeys: string): TsdDataRecord;
+var
+  GLJRec: TsdDataRecord;
+begin
+  Result := nil;
+  GLJRec := LocateGLJ(AKeys);
+  if GLJRec <> nil then
+    Result := sdsMachineDetail.Locate(SID, GLJRec.ValueByName(SID).AsInteger);
+end;
+
 function TScUnitPriceLib.LocateMaterial(AKeys: string): TsdDataRecord;
 var
   GLJRec: TsdDataRecord;
@@ -682,6 +697,10 @@ begin
     begin
       SaveMachine(ARecord, AKey3, Sender, AKind);
     end
+    else if SameText(ATableName, SUMachineDetail) then
+    begin
+      SaveMachineDetail(ARecord, AKey3, AKey4, Sender, AKind);
+    end
     else if SameText(ATableName, SMachineLabours) then
     begin
       SaveMachineLabours(ARecord, Sender, AKind);
@@ -956,6 +975,99 @@ begin
   end;
 end;
 
+procedure TScUnitPriceLib.SaveMachineDetail(ARecord: TsdDataRecord;
+  AKeys, AOwnerKeys: string; Sender: TObject; AKind: TUpdateKind);
+var
+  Source: TScMachineDetailRecord;
+  Target, GLJRec, ProjectMachineRec: TsdDataRecord;
+  ProjectGLJRec: TScProjectGLJRecord;
+  bChanged: Boolean;
+  strCode, strName, strSpecs, strUnit: string;
+begin
+  case AKind of
+    ukModify, ukInsert:
+    begin
+      Source := TScMachineDetailRecord(ARecord);
+      if not ResolveGLJKeys(AKeys, strCode, strName, strSpecs, strUnit) then
+        Exit;
+      Target := LocateMachine(AKeys);
+      // 单价/数量都相同则认为没有发生改变
+      if (Target <> nil) and
+          (Target.ValueByName(SBudgetPrice).AsCurrency = Source.BudgetPrice.AsCurrency) and
+          (Target.ValueByName(SQuantity).AsCurrency = Source.Quantity.AsCurrency) then
+        Exit;
+      if Target = nil then
+      begin
+        // GLJRec(指机械对应的GLJList表记录)不存在的话需要从原项目中读取并强行同步
+        GLJRec := LocateGLJ(AKeys);
+        if GLJRec = nil then
+        begin
+          ProjectGLJRec := TScProjectUnitPriceLib(Sender).ProjectGLJ.LocateGLJ(AKeys);
+          if ProjectGLJRec <> nil then
+          begin
+            SaveGLJ(ProjectGLJRec, Sender, ukInsert);
+            // 再次查找
+            GLJRec := LocateGLJ(AKeys);
+            if GLJRec = nil then
+              raise EScUnitPriceLib.Create('Can not find machine OwnerGLJ');
+          end
+          else
+            raise EScUnitPriceLib.Create('Can not find machine OwnerGLJ');
+          // MachineDetail表中的OwnerGLJ
+          ProjectMachineRec := TScProjectUnitPriceLib(Sender).ProjectGLJ.LocateGLJ(AOwnerKeys);
+          if ProjectMachineRec <> nil then
+          begin
+            SaveGLJ(ProjectMachineRec, Sender, ukInsert);
+            // 再次查找
+            ProjectMachineRec := LocateGLJ(AKeys);
+            if ProjectMachineRec = nil then
+              raise EScUnitPriceLib.Create('Can not find MachineDetail OwnerGLJ');
+          end
+          else
+            raise EScUnitPriceLib.Create('Can not find MachineDetail OwnerGLJ');
+        end;
+        AKind := ukInsert;
+        Target := sdsMachinePrice.Add(True);
+        Target.ValueByName(SID).AsInteger := GLJRec.ValueByName(SID).AsInteger;
+        Target.ValueByName(SCode).AsString := GLJRec.ValueByName(SCode).AsString;
+        Target.ValueByName(SName).AsString := GLJRec.ValueByName(SName).AsString;
+        Target.ValueByName(SSpecs).AsString := GLJRec.ValueByName(SSpecs).AsString;
+        Target.ValueByName(SUnit).AsString := GLJRec.ValueByName(SUnit).AsString;
+        Target.ValueByName(SOwnerID).AsInteger := ProjectMachineRec.ValueByName(SOwnerID).AsInteger;
+        Target.ValueByName(SOwnerCode).AsString := ProjectMachineRec.ValueByName(SOwnerCode).AsString;
+        Target.ValueByName(SOwnerName).AsString := ProjectMachineRec.ValueByName(SOwnerName).AsString;
+        Target.ValueByName(SOwnerSpecs).AsString := ProjectMachineRec.ValueByName(SOwnerSpecs).AsString;
+        Target.ValueByName(SOwnerUnit).AsString := ProjectMachineRec.ValueByName(SOwnerUnit).AsString;
+      end
+      else
+        Target.BeginUpdate;
+      try
+        bChanged := (AKind = ukInsert) or ((AKind = ukModify) and
+          ((Target.ValueByName(SBudgetPrice).AsCurrency <> Source.BudgetPrice.AsCurrency) or
+          (Target.ValueByName(SQuantity).AsCurrency <> Source.Quantity.AsCurrency)));
+
+        Target.ValueByName(SBudgetPrice).AsCurrency := Source.BudgetPrice.AsCurrency;
+        Target.ValueByName(SBasePrice).AsCurrency := Source.BasePrice.AsCurrency;
+        Target.ValueByName(SQuantity).AsCurrency := Source.Quantity.AsCurrency;
+      finally
+        Target.EndUpdate;
+      end;
+      if bChanged then
+        SyncLibs(SUMachineDetail, '', Target, nil, '', '', AKeys, '', Sender, AKind);
+    end;
+    ukDelete:
+    begin
+      Target := LocateMachine(AKeys);
+      if Target <> nil then
+      begin
+        SyncLibs(SUMachineDetail, '', Target, nil, '', '', AKeys, '', Sender, AKind);
+        sdsMachinePrice.Remove(Target);
+        Target := nil;
+      end;
+    end;
+  end;
+end;
+
 procedure TScUnitPriceLib.SaveMachineLabours(ARecord: TsdDataRecord;
   Sender: TObject; AKind: TUpdateKind);
 var