Ver código fonte

在线审批。

CSL 9 anos atrás
pai
commit
4f93e54f1a

+ 2 - 2
Dprs/CSL/Measure_Cloud.dof

@@ -115,7 +115,7 @@ AutoIncBuild=1
 MajorVer=3
 MinorVer=1
 Release=3
-Build=1060
+Build=1063
 Debug=0
 PreRelease=0
 Special=0
@@ -126,7 +126,7 @@ CodePage=936
 [Version Info Keys]
 CompanyName=珠海纵横创新软件有限公司
 FileDescription=纵横结算决算计量一体化云版
-FileVersion=3.1.3.1060
+FileVersion=3.1.3.1063
 InternalName=Measure
 LegalCopyright=版权所有(C) 珠海纵横创新软件有限公司 2003-2014。保留所有权利。
 LegalTrademarks=Measure

+ 24 - 1
Dprs/CSL/Measure_Cloud.dpr

@@ -153,7 +153,30 @@ uses
   BaseClipboard in '..\..\Units\BaseClipboard.pas',
   SelectDetailGLsFrm in '..\..\Forms\SelectDetailGLsFrm.pas' {SelectDetailGLsForm},
   DealPayPlanFrm in '..\..\Forms\DealPayPlanFrm.pas' {DealPayPlanForm},
-  mProgressProFrm in '..\..\Forms\mProgressProFrm.pas' {ProgressProForm};
+  mProgressProFrm in '..\..\Forms\mProgressProFrm.pas' {ProgressProForm},
+  tpBaseGatherData in '..\..\TenderPartition\tpBaseGatherData.pas',
+  tpGatherGcl in '..\..\TenderPartition\tpGatherGcl.pas',
+  tpGatherTree in '..\..\TenderPartition\tpGatherTree.pas',
+  tpMainData in '..\..\TenderPartition\tpMainData.pas',
+  tpMainFrm in '..\..\TenderPartition\tpMainFrm.pas' {tpMainForm},
+  tpNoPegDm in '..\..\TenderPartition\tpNoPegDm.pas' {tpNoPegData: TDataModule},
+  tpPartTender in '..\..\TenderPartition\tpPartTender.pas',
+  tpPartTenderFme in '..\..\TenderPartition\tpPartTenderFme.pas' {tpPartTenderFrame: TFrame},
+  tpPartTenderSet in '..\..\TenderPartition\tpPartTenderSet.pas',
+  tpPartTenderSetFme in '..\..\TenderPartition\tpPartTenderSetFme.pas' {tpPartTenderSetFrame: TFrame},
+  tpPeg in '..\..\TenderPartition\tpPeg.pas',
+  tpPeg_GclDm in '..\..\TenderPartition\tpPeg_GclDm.pas' {tpPeg_GclData: TDataModule},
+  tpPeg_GclFme in '..\..\TenderPartition\tpPeg_GclFme.pas' {tpPeg_GclFrame: TFrame},
+  tpPegBlock in '..\..\TenderPartition\tpPegBlock.pas',
+  tpPegGclGatherDm in '..\..\TenderPartition\tpPegGclGatherDm.pas' {tpPegGclGatherData: TDataModule},
+  tpPegGclGatherFme in '..\..\TenderPartition\tpPegGclGatherFme.pas' {tpPegGclGatherFrame: TFrame},
+  tpPegPartSettingFrm in '..\..\TenderPartition\tpPegPartSettingFrm.pas' {tpPegPartSettingForm},
+  tpPricePartSettingFrm in '..\..\TenderPartition\tpPricePartSettingFrm.pas' {tpPricePartSettingForm},
+  tpSelectTenderDm in '..\..\TenderPartition\tpSelectTenderDm.pas' {tpSelectTenderData: TDataModule},
+  tpSelectTenderNode in '..\..\TenderPartition\tpSelectTenderNode.pas',
+  tpSelectTendersFrm in '..\..\TenderPartition\tpSelectTendersFrm.pas' {SelectTendersForm},
+  tpTrialPegInputFrm in '..\..\TenderPartition\tpTrialPegInputFrm.pas' {TrialPegInputForm},
+  mPegFilter in '..\..\Units\mPegFilter.pas';
 
 {$R *.res}
 

BIN
Dprs/CSL/Measure_Cloud.res


+ 2 - 2
Frames/ProjectFme.pas

@@ -983,7 +983,7 @@ begin
 
         if ProjectData.PhaseIndex = 0 then   // 0ºĄ̊ÕË£¬ÏÖÒÑ·ÏÆú
         begin
-          MainForm.ProjectManagerFrame.ShowProjWebInfoTop(0);
+          MainForm.ProjectManagerFrame.ShowProjectInfoTop(0);
         end
         else
         Begin
@@ -991,7 +991,7 @@ begin
           vRec.BeginUpdate;
           vRec.ValueByName('WebMD5').AsString := sMD5_JL;
           vRec.EndUpdate;
-          MainForm.ProjectManagerFrame.ShowProjWebInfoTop;
+          MainForm.ProjectManagerFrame.ShowProjectInfoTop;
 
           if ProjectData.CurUserIsAuthor then
           begin

+ 227 - 167
Frames/ProjectManagerFme.pas

@@ -7,10 +7,12 @@ uses
   NewProjectFrm,
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, ZjGridDBA, ZJGrid, ComCtrls, ToolWin, ActnList,
-  dxBar, sdGridDBA, sdGridTreeDBA, sdIDTree, ExtCtrls,
+  dxBar, sdGridDBA, sdGridTreeDBA, sdIDTree, CslJson, ExtCtrls,
   StdCtrls, sdDB, CslButton, OrderCheckerFme, Contnrs;
 
 type
+  TStrArr = array of string;
+
   TProjectManagerFrame = class(TFrame)
     ToolBar: TToolBar;
     tobtnOpen: TToolButton;
@@ -89,28 +91,38 @@ type
   private
     FProjectManagerData: TProjectManagerData;
 
-    FID: Integer;
-    FWebID: Integer;
-    FWebAuthorID: Integer;
-    FWebOwnerID: Integer;
-    FWebMD5: string;
-    FBidName: string;
+                                             // Chenshilong,2016.03.24
+                                             // 这部分线上和本地一致,无需区分
+    FID: Integer;                            // 本地标段文件ID
+    FWebID: Integer;                         // 关联服务器用的ID(服务器有自己的ID体系)
+    FWebAuthorID: Integer;                   // 编制人
+    FWebOwnerID: Integer;                    // 业主
+
+                                             // 本地存储值、线上存储值。线上修改后,需要同步到本地
+    FWebMD5_Local: string;                   // 本地存储的MD5
+    FWebMD5_OnLine: string;                  // 线上存储的最新的MD5(下同)
+    FWebBidName_Local: string;               // 标段名 (当无法同线上取得联系时,本地需要用到该名称来提示)
+    FWebBidName_OnLine: string;
+
+    FWebFolder_OnLine: string;               // 这个命名不妥,但很直观。线上的项目名称、项目类型概念跟本地颠倒,很混乱。
+    FWebSubFolder_OnLine: string;
 
-    FWebProjCtgyName: string;
     FWebOwnerCompany: string;
-    FWebProjectName: string;
     FWebOwnerRole: string;
     FWebOwnerName: string;
+
+    FWebCheckStatusMy: TCheckStatus;          // 登陆用户在当前项目中的工作状态。
+    FWebCheckStatusProject: TCheckStatus;     // 项目的审核状态。
+
+    FOnLineCheckerBegin: Integer;               // 线上审批的起始人。 010110111 起7止9。 0101101110 起0止0。
+    FOnLineCheckerEnd: Integer;                 // 线上审批的截止人。
+
     FPhaseTotal: Integer;
     FPhaseNo: Integer;
-    FMyCheckStatus: TCheckStatus;            // 登陆用户在当前项目中的工作状态。
-    FProjectCheckStatus: TCheckStatus;       // 项目的审核状态。
 
-    FCurPos: Integer;                        // 用来控制审核人的添加位置
+    FCurPos: Integer;                         // 用来控制审核人的添加位置
     FCheckerList: TObjectList;
 
-
-
     function ReceiveFile(const AFileName: string; AFileMD5: string = ''; ANeedLock: Boolean = False): Boolean;
     function ImportFile(const AFileName: string; AFileMD5: string = ''): Boolean;
     procedure ConnectButtonWithAction;
@@ -120,7 +132,7 @@ type
     function IsUnEmptyLeafProject(ANode: TsdIDTreeNode): Boolean;
     function CheckOpened(ANode: TsdIDTreeNode): Boolean;
     procedure SetPropertyVisible(AVisible: Boolean);
-    procedure SearchAndShowProjAllWebInfo(ARec: TsdDataRecord);
+    procedure ShowProjectInfoTopAndCheckers;
     // 网络上的目录结构,本地有则定位,没有则创建。
     procedure CheckWebFolders(AFolderID, ASubFolderID: Integer;
       AFolderName, ASubFolderName: string);
@@ -128,7 +140,6 @@ type
     procedure CheckBidName(AID: Integer; ANewBidName: string); overload;
     procedure CheckBidName(AUserID, AWebID: Integer; ANewBidName: string); overload;
     procedure ClearLocalValues;
-    procedure GetLocalValues; overload;
     procedure GetLocalValues(ARec: TsdDataRecord); overload;
     // 用户ID、网络标段ID、Type=1可以定位一个标段。
     procedure GetLocalValues(AUserID, AWebID: Integer); overload;
@@ -136,24 +147,28 @@ type
     procedure DoBatchReceiveOnline(ARequestType: Integer);
     function LocalMD5(AUserID, AWebID: Integer): string;
     procedure BubbleSortProjects;
+    // AReceiveKind: 1 接收; 2 导入
+    function FileDownAndReceive(ADownURL: string; AReceiveKind: Integer): Boolean;
+    // 线上审批的起止人
+    procedure OnLineChecker(AAr: TOVArr; var ABegin, AEnd: Integer);
   public
     constructor Create(AOwner: TComponent); override;
     destructor Destroy; override;
     procedure DoBatchReceiveAllOnline;
     // AType: -2 繁忙; -1 正常读取; 0 第0期; 1 第1期。
-    procedure ShowProjWebInfoTop(AType: Integer = -1);
+    procedure ShowProjectInfoTop(AType: Integer = -1);
     function Rec(AProjectID: Integer): TsdDataRecord;
     function CurRec: TsdDataRecord;
     function CurRecAttachmentPath: string;
     function AttachmentFileCountsWithoutManageFile(ANode: TsdIDTreeNode): Integer;
-    property ProjectCheckStatus: TCheckStatus read FProjectCheckStatus;
+    property ProjectCheckStatus: TCheckStatus read FWebCheckStatusProject;
   end;
 
 implementation
 
 uses
   MainFrm, UtilMethods, ProjectCommands, Globals, ConfigDoc, ConstUnit,
-  WebNewTenderFrm, PHPWebDm, Math, CslJson, mProgressFrm, ProgressHintFrm,
+  WebNewTenderFrm, PHPWebDm, Math, mProgressFrm, ProgressHintFrm,
   ShellAPI;
 
 {$R *.dfm}
@@ -237,13 +252,10 @@ var
 
   function CanOpen: Boolean;
   var
-    sSearchURL, sDownURL, sFolder, sSubFolder, sNewName, sMD5,
+    sSearchURL, sDownURL,
     sMD5_UnLock, sError, sLocalFile: string;
     iSearch, iFolderID, iSubFolderID: Integer;
 
-    bLock, bCanImp: Boolean;
-    vFileCheck: TTenderFileChecker;
-
     function HasWebBidInfo(AWebID: Integer): Boolean;
     var vArr: array of string;
       iResult: Integer;
@@ -262,96 +274,34 @@ var
 
     // 先按正常接口找到最新的MD5码看是否需要更新
     sSearchURL := Format('%stender/get/%d/update', [PHPWeb.MeasureURL, FWebID]);
-    iSearch := SearchFileOnline(sSearchURL, sDownURL, sFolder, sSubFolder, sNewName, sMD5, sError, iFolderID, iSubFolderID);
+    iSearch := SearchFileOnline(sSearchURL, sDownURL, FWebFolder_OnLine, FWebSubFolder_OnLine, FWebBidName_OnLine, FWebMD5_OnLine, sError, iFolderID, iSubFolderID);
 
     if iSearch = 1 then
     begin
       try
-        CheckWebFolders(iFolderID, iSubFolderID, sFolder, sSubFolder);
-        CheckBidName(FID, sNewName);
+        CheckWebFolders(iFolderID, iSubFolderID, FWebFolder_OnLine, FWebSubFolder_OnLine);
+        CheckBidName(FID, FWebBidName_OnLine);
       finally
         if vSel <> nil then
           vSel.LocateInControl;
       end;
 
       // 打开前一定要先下载最新的标段文件(无论审核有没有通过)
-      if sMD5 <> FWebMD5 then
-      begin
-        // 下载
-        sLocalFile := PHPWeb.UserPath + ExtractFileName(sDownURL);
-        if not PHPWeb.DownFile(sDownURL, sLocalFile) then
-        begin
-          sHint := Format('云端已找到"%s"的新文件,但由于网络原因下载失败,请重试!', [FBidName]);
-          Application.MessageBox(PChar(sHint), '警告', MB_OK + MB_ICONWARNING);
-          Exit;
-        end;
-
-        // 接收更新
-        bLock := (FWebAuthorID = PHPWeb.UserID) or ((FWebAuthorID <> PHPWeb.UserID) and (FMyCheckStatus <> csChecking));
-        if not ReceiveFile(sLocalFile, sMD5, bLock) then
-        begin
-          sHint := Format('已从云端下载新的"%s"到本地[%s],但接收失败,请删除该项目然后重新从云端获取!', [FBidName, sLocalFile]);
-          Application.MessageBox(PChar(sHint), '警告', MB_OK + MB_ICONWARNING);
-          Exit;
-        end;
-      end;
-      DeleteFile(sLocalFile);
+      if FWebMD5_OnLine <> FWebMD5_Local then
+        if not FileDownAndReceive(sDownURL, 1) then Exit;
 
       // 编制人且项目末通过
-      if (FWebAuthorID = PHPWeb.UserID) and (FProjectCheckStatus = csNotPass) then
+      if (FWebAuthorID = PHPWeb.UserID) and (FWebCheckStatusProject = csNotPass) then
       begin
-        sHint := '本期计量审批不通过,你现在可以:' + #10#13 +
-        '点击【是(Y)】重新开始本期计量,软件将打开本期上报时的数据,开始重新计量;' + #10#13 +
-        '点击【否(N)】查看不通过计量,软件将打开本期最后审批的数据,重新打开标段' + 
-        '可再次打开本确认窗口。';
+        sHint := '本期计量审批不通过,你现在可以:' + #10#13 + '点击【是(Y)】重新开始本期计量,软件将打开本期上报时的数据,开始重新计量;' +
+          #10#13 +'点击【否(N)】查看不通过计量,软件将打开本期最后审批的数据,重新打开标段' + '可再次打开本确认窗口。';
         if Application.MessageBox(PChar(sHint), '询问', MB_YESNO + MB_ICONQUESTION) = ID_Yes then
         begin
           sSearchURL := Format('%suser/create/%d/%d/new/audit', [PHPWeb.MeasureURL, FWebID, FPhaseNo]);
-          case SearchFileOnline(sSearchURL, sDownURL, sFolder, sSubFolder, sNewName, sMD5_UnLock, sError, iFolderID, iSubFolderID) of
-            1: {注意这里的MD5码应取最终审核不通过项目的,否则会带来下载循环问题。
-                问题描述:
-                ①编制人运行软件,双击项目,发现审核不通过,自动下载无锁文件,开始新一期,保存关闭。
-                ②编制人再次运行软件,双击项目,MD5码不同,自动下载旧的审核不通过文件,覆盖本地。
-                ③编制人再次运行软件,双击项目,发现审核不通过,重复①,循环....
-                问:①那里下载无锁文件后不能改成新的MD5码吗?
-                答:不能,因为审核人的项目会变成无锁文件,看不到不通过项目。MD5码只能在上传后更新。
-                且编制人有个交互界面2种选择:a.下载更新不通过项目查看;b.下载更新无锁文件开始新一期。
-                }
+          case SearchFileOnline(sSearchURL, sDownURL, FWebFolder_OnLine, FWebSubFolder_OnLine, FWebBidName_OnLine, sMD5_UnLock, sError, iFolderID, iSubFolderID) of
+            1:
             begin
-              // 下载
-              sLocalFile := PHPWeb.UserPath + ExtractFileName(sDownURL);
-              if not PHPWeb.DownFile(sDownURL, sLocalFile) then
-              begin
-                sHint := '云端已找到原报上传的无锁文件,但因网络出错无法下载,本次操作已取消。请重试!';
-                Application.MessageBox(PChar(sHint), '警告', MB_OK + MB_ICONWARNING);
-                Exit;
-              end;
-
-
-              // 导入更新-------------------------------------------------------
-
-              // 导入前须检测无锁文件中仅含有原报数据
-              vFileCheck := TTenderFileChecker.Create;
-              try
-                // 有一期以上数据,且最新期数据审核状态为原报
-                bCanImp := vFileCheck.CheckFileValid(sLocalFile)
-                    and (vFileCheck.PhaseCount > 0) and (vFileCheck.AuditStatus = 0);
-                if not bCanImp then
-                begin
-                  Application.MessageBox(PChar('已从云端下载原报上传的无锁文件到本地,但文件有错误,禁止导入!请致电纵横服务人员以获取帮助。'), '警告', MB_OK + MB_ICONWARNING);
-                  Exit;
-                end;
-              finally
-                vFileCheck.Free;
-              end;
-
-              if not ImportFile(sLocalFile, sMD5) then
-              begin
-                Application.MessageBox(PChar('已从云端下载原报上传的无锁文件到本地,但导入失败!请重试。'), '警告', MB_OK + MB_ICONWARNING);
-                Exit;
-              end;
-              
-              // 导入更新---------------------------------↑↑↑↑↑↑↑↑↑↑↑
+              if not FileDownAndReceive(sDownURL, 2) then Exit;
             end;
 
             0, -1:
@@ -368,14 +318,14 @@ var
     begin
       if not HasWebBidInfo(FWebID) then
       begin
-        sHint :='该项目[' + FBidName + ']在云端已被删除,点击"确定"后,可手动删除该项目。';
+        sHint :='该项目[' + FWebBidName_Local + ']在云端已被删除,点击"确定"后,可手动删除该项目。';
         Application.MessageBox(PChar(sHint), '提示', MB_OK + MB_ICONINFORMATION);
         Exit;
       end;
     end
     else if (iSearch = 0) or (iSearch = -1) then
     begin
-      sHint := sError + '(因网络出错,无法检测[' + FBidName + ']在云端是否有更新,本次操作已取消,请重试)。';
+      sHint := sError + '(因网络出错,无法检测[' + FWebBidName_Local + ']在云端是否有更新,本次操作已取消,请重试)。';
       Application.MessageBox(PChar(sHint), '警告', MB_OK + MB_ICONWARNING);
       Exit;
     end;
@@ -392,7 +342,7 @@ begin
 
     if G_IsCloud then
     begin
-      GetLocalValues;
+      GetLocalValues(CurRec);
       // 以下这段已经包含在MainForm.OpenProject(vRec)中了,但在调用这句之前,网络版要提前用一下。
       if MainForm.HasOpened(FID) then
       begin
@@ -410,7 +360,7 @@ begin
     begin
       if not MainForm.CurProjectFrame.CheckFileAndCloudChekerList then
       begin
-        sHint := '项目校验:“' + FBidName + '”文件中的审核人和云端的审核人不一致,' +
+        sHint := '项目校验:“' + FWebBidName_OnLine + '”文件中的审核人和云端的审核人不一致,' +
           '禁止继续操作,项目即将关闭!请删除本地项目重新从云端获取,' +
           '重新获取后如果仍然存在同样的问题,请联系纵横服务人员以寻求帮助。';
         Application.MessageBox(PChar(sHint), '文件错误', MB_OK +MB_ICONWARNING);
@@ -630,13 +580,13 @@ procedure TProjectManagerFrame.actnNewTenderExecute(Sender: TObject);
         FWebOwnerName := vArr[1];
         FWebOwnerCompany := vArr[2];
         FWebOwnerRole := vArr[8];
-        FWebProjectName := vArr[6];
-        FWebProjCtgyName := vArr[7];
+        FWebFolder_OnLine := vArr[6];
+        FWebSubFolder_OnLine := vArr[7];
 //          WebOwnerImage := vArr[9];
 //          WebOwnerPhone := vArr[3];
 //          WebOwnerMobile := vArr[4];
 //          WebOwnerQQ := vArr[5];
-        ShowProjWebInfoTop(0);
+        ShowProjectInfoTop(0);
         FProjectManagerData.Save;
         MainForm.OpenProject(vRec);
       end;
@@ -765,7 +715,7 @@ begin
     begin
       CreateProgress('云端读取项目信息');
       try
-        SearchAndShowProjAllWebInfo(CurRec);
+        ShowProjectInfoTopAndCheckers;
       finally
         CloseProgress;
       end;
@@ -1027,9 +977,9 @@ begin
   end;
 end;
 
-procedure TProjectManagerFrame.SearchAndShowProjAllWebInfo(ARec: TsdDataRecord);
+procedure TProjectManagerFrame.ShowProjectInfoTopAndCheckers;
 var
-  vPSArr: array[0..7] of string;
+  vPSArr: TStrArr;
   vCArr: TOVArr;    // Checkers
   vChecker: TOrderCheckerFrame;
   sPicPath, sURL: string;
@@ -1060,7 +1010,7 @@ var
       TOrderCheckerFrame(sbChecker.Controls[k]).Order := k + 1;
   end;
 
-  procedure RefreshProjectCheckers;
+  procedure ShowProjectCheckers;
   var i, j, n: Integer;
     vOwner: array of string;  // 业主信息
   begin
@@ -1074,7 +1024,7 @@ var
     for i := Low(vCArr) to High(vCArr) do
     begin
       if StrToInt(vCArr[i, 0]) = PHPWeb.UserID then
-        FMyCheckStatus := TCheckStatus(StrToInt(vCArr[i, 5])-1);
+        FWebCheckStatusMy := TCheckStatus(StrToInt(vCArr[i, 5])-1);
 
       if StrToInt(vCArr[i, 0]) = FWebOwnerID then
       begin
@@ -1083,32 +1033,36 @@ var
 
         Continue;
       end;
+      
       AddChecker(cftChecker, vCArr[i]);
     end;
     if vOwner[0] <> '' then
       AddChecker(cftOwner, vOwner);
     RepairOrder;
+
+    OnLineChecker(vCArr, FOnLineCheckerBegin, FOnLineCheckerEnd);
   end;
 
 begin
-  GetLocalValues(ARec);
+  GetLocalValues(CurRec);
   if FWebID = 0 then Exit;
+  SetLength(vPSArr, 8);
   sURL := Format('%smeasure/status/%d/get', [PHPWeb.MeasureURL, FWebID]);
   if PHPWeb.Search(sURL, [''], [''], 3, vPSArr, vCArr) = 1 then
   begin
     LockWindowUpdate(pnlWeb.Handle);
     try
       FPhaseNo := StrToInt(vPSArr[0]);
-      FProjectCheckStatus := TCheckStatus(StrToInt(vPSArr[1])-1);
+      FWebCheckStatusProject := TCheckStatus(StrToInt(vPSArr[1])-1);
       FPhaseTotal := StrToInt(vPSArr[2]);
-      FWebProjectName := vPSArr[3];
-      FWebProjCtgyName := vPSArr[4];
+      FWebFolder_OnLine := vPSArr[3];
+      FWebSubFolder_OnLine := vPSArr[4];
       FWebOwnerName := vPSArr[5];
       FWebOwnerCompany := vPSArr[6];
       FWebOwnerRole := vPSArr[7];
 
-      ShowProjWebInfoTop;
-      RefreshProjectCheckers;
+      ShowProjectInfoTop;
+      ShowProjectCheckers;
     finally
       LockWindowUpdate(0);
     end;
@@ -1116,29 +1070,29 @@ begin
   else
   begin
     FPhaseNo := 0;
-    FProjectCheckStatus := csNotBegin;
+    FWebCheckStatusProject := csNotBegin;
     FPhaseTotal := 0;
-    FWebProjectName := '';
-    FWebProjCtgyName := '';
+    FWebFolder_OnLine := '';
+    FWebSubFolder_OnLine := '';
     FWebOwnerName := '';
     FWebOwnerCompany := '';
     FWebOwnerRole := '';
 
-    ShowProjWebInfoTop;
+    ShowProjectInfoTop;
 
     sbChecker.Height := 0;
   end;
 end;
 
-procedure TProjectManagerFrame.ShowProjWebInfoTop(AType: Integer);
+procedure TProjectManagerFrame.ShowProjectInfoTop(AType: Integer);
 
   procedure ShowOwner;
   begin
-    lblBidName.Caption := FBidName;
+    lblBidName.Caption := FWebBidName_Local;
     lblBidName.Update;
-    lblProjName.Caption := FWebProjectName;
+    lblProjName.Caption := FWebFolder_OnLine;
     lblProjName.Update;
-    lblWebProjCtgyName.Caption := FWebProjCtgyName;
+    lblWebProjCtgyName.Caption := FWebSubFolder_OnLine;
     lblWebProjCtgyName.Update;
     lblOnwerName.Caption := FWebOwnerName;
     lblOnwerName.Update;
@@ -1160,7 +1114,7 @@ procedure TProjectManagerFrame.ShowProjWebInfoTop(AType: Integer);
     lblPeriodTotal.Left := lblPeriodState.Left + lblPeriodState.Width + 3;
   end;
 begin
-  GetLocalValues;
+  GetLocalValues(CurRec);
   case AType of
     -2:
     begin
@@ -1170,7 +1124,7 @@ begin
     -1:
     begin
       ShowOwner;
-      ShowStatus(FPhaseNo, FProjectCheckStatus);
+      ShowStatus(FPhaseNo, FWebCheckStatusProject);
     end;
     0:
     begin
@@ -1293,11 +1247,9 @@ end;
 
 procedure TProjectManagerFrame.DoBatchReceiveOnline(ARequestType: Integer);
 var
-  sURL, sFolder, sSubFolder, sMD5, sName, sHint, sLocalFile: string;
-  vMyCheckStatus: TCheckStatus;
+  sURL, sHint: string;
   vArr: TOVArr;
-  bLock: Boolean;
-  i, iWebID, iFolderID, iSubFolderID, iAuthorID: Integer;
+  i, iFolderID, iSubFolderID: Integer;
 begin
   // 查询等待我审核的标段文件,杰哥说分三种:①业主未审核 ②业主审核中 ③审核人审核中 (为什么加①?问杰哥)
   case PHPWeb.Search(PHPWeb.MeasureURL + 'user/get/audit/project', ['audituid', 'RequestType'],
@@ -1309,39 +1261,22 @@ begin
         for i := Low(vArr) to High(vArr) do
         begin
           sURL := vArr[i, 0];
-          sFolder := vArr[i, 1];
-          sSubFolder := vArr[i, 2];
-          sMD5 := vArr[i, 3];
-          iWebID := StrToInt(vArr[i, 5]);
+          FWebFolder_OnLine := vArr[i, 1];
+          FWebSubFolder_OnLine := vArr[i, 2];
+          FWebMD5_OnLine := vArr[i, 3];
+          FWebID := StrToInt(vArr[i, 5]);
           iFolderID := StrToInt(vArr[i, 6]);
           iSubFolderID := StrToInt(vArr[i, 7]);
-          vMyCheckStatus := TCheckStatus(StrToInt(vArr[i, 8])-1);               // vArr[i, 4]项目审核状态;vArr[i, 8]当前登陆用户的审核状态
-          iAuthorID := StrToInt(vArr[i, 9]);                                    // 编制人ID
-          sName := vArr[i, 10];                                                 // 标段名称
-          
-          CheckWebFolders(iFolderID, iSubFolderID, sFolder, sSubFolder);
-          CheckBidName(PHPWeb.UserID, iWebID, sName);
-
-          if sMD5 <> LocalMD5(PHPWeb.UserID, iWebID) then
-          begin
-            // 下载
-            sLocalFile := PHPWeb.UserPath + ExtractFileName(sURL);
-            if not PHPWeb.DownFile(sURL, sLocalFile) then
-            begin
-              sHint := Format('云端已找到"%s"的新文件,但由于网络原因下载失败!请点击菜单“同步更新我参与的全部项目”重新下载!', [sName]);
-              Application.MessageBox(PChar(sHint), '系统提醒', MB_OK + MB_ICONWARNING);
-            end;
+          FWebCheckStatusMy := TCheckStatus(StrToInt(vArr[i, 8])-1);      // vArr[i, 4]项目审核状态;vArr[i, 8]当前登陆用户的审核状态
+          FWebAuthorID := StrToInt(vArr[i, 9]);
+          FWebBidName_OnLine := vArr[i, 10];
+          FWebMD5_Local := LocalMD5(PHPWeb.UserID, FWebID);
 
-            // 接收更新
-            bLock := (iAuthorID = PHPWeb.UserID) or ((iAuthorID <> PHPWeb.UserID) and (vMyCheckStatus <> csChecking));
-            if not ReceiveFile(sLocalFile, sMD5, bLock) then
-            begin
-              sHint := Format('已从云端下载新的"%s"到本地,但接收失败,请删除该项目然后重新从云端获取!', [sName]);
-              Application.MessageBox(PChar(sHint), '系统提醒', MB_OK + MB_ICONWARNING);
-              Exit;
-            end;
-            DeleteFile(sLocalFile);
-          end;
+          CheckWebFolders(iFolderID, iSubFolderID, FWebFolder_OnLine, FWebSubFolder_OnLine);
+          CheckBidName(PHPWeb.UserID, FWebID, FWebBidName_OnLine);
+
+          if FWebMD5_OnLine <> FWebMD5_Local then
+            if not FileDownAndReceive(sURL, 1) then Exit;
         end;
 
         BubbleSortProjects;
@@ -1447,11 +1382,6 @@ begin
   end;
 end;
 
-procedure TProjectManagerFrame.GetLocalValues;
-begin
-  GetLocalValues(CurRec);
-end;
-
 
 procedure TProjectManagerFrame.GetLocalValues(ARec: TsdDataRecord);
 begin
@@ -1468,8 +1398,8 @@ begin
     FWebID := ARec.ValueByName('WebID').AsInteger;
     FWebAuthorID := ARec.ValueByName('WebAuthorID').AsInteger;
     FWebOwnerID := ARec.ValueByName('WebOwnerID').AsInteger;
-    FWebMD5 := ARec.ValueByName('WebMD5').AsString;
-    FBidName := ARec.ValueByName('Name').AsString;
+    FWebMD5_Local := ARec.ValueByName('WebMD5').AsString;
+    FWebBidName_Local := ARec.ValueByName('Name').AsString;
   end;
 end;
 
@@ -1509,8 +1439,8 @@ begin
   FWebID := -1;
   FWebAuthorID := -1;
   FWebOwnerID := -1;
-  FWebMD5 := '';
-  FBidName := '';
+  FWebMD5_Local := '';
+  FWebBidName_Local := '';
 end;
 
 
@@ -1718,4 +1648,134 @@ begin
   end;
 end;
 
+function TProjectManagerFrame.FileDownAndReceive(ADownURL: string; AReceiveKind: Integer): Boolean;
+var sLocalFile, sHint: string;
+  bLock, bCanImp, bIsOwner: Boolean;
+  vFileCheck: TTenderFileChecker;
+begin
+  Result := False;
+
+  // 下载
+  sLocalFile := PHPWeb.UserPath + ExtractFileName(ADownURL);
+  if not PHPWeb.DownFile(ADownURL, sLocalFile) then
+  begin
+    if AReceiveKind = 1 then
+      sHint := Format('云端已找到[%s]的新文件,但由于网络原因下载失败!请重试!', [FWebBidName_Local])
+    else if AReceiveKind = 2 then
+      sHint := '云端已找到原报上传的无锁文件,但因网络出错无法下载,本次操作已取消。请重试!';
+
+    Application.MessageBox(PChar(sHint), '系统提醒', MB_OK + MB_ICONWARNING);
+    Exit;
+  end;
+
+  // 接收更新
+  if AReceiveKind = 1 then
+  begin
+    bLock := (FWebAuthorID = PHPWeb.UserID) or
+             ((FWebAuthorID <> PHPWeb.UserID) and (FWebCheckStatusMy <> csChecking));
+    bIsOwner := FWebOwnerID = PHPWeb.UserID;
+    if not ReceiveFile(sLocalFile, FWebMD5_OnLine, bLock) then
+//    if not ReceiveForLost(sLocalFile, FWebMD5_OnLine, bLock, FOnLineCheckerBegin, FOnLineCheckerEnd, bIsOwner) then
+    begin
+      sHint := Format('已从云端下载新的[%s]到本地[%s],但接收失败,请删除该项目然后重新从云端获取!', [FWebBidName_Local, sLocalFile]);
+      Application.MessageBox(PChar(sHint), '系统提醒', MB_OK + MB_ICONWARNING);
+      Exit;
+    end;
+  end
+
+  // 导入更新
+  else if AReceiveKind = 2 then
+  begin
+    // 有时无锁文件出错:包含了1审2审的数据。所以导入前须检测。
+    vFileCheck := TTenderFileChecker.Create;
+    try
+      // 有一期以上数据,且最新期数据审核状态为原报
+      bCanImp := vFileCheck.CheckFileValid(sLocalFile) and (vFileCheck.PhaseCount > 0) and (vFileCheck.AuditStatus = 0);
+      if not bCanImp then
+      begin
+        Application.MessageBox(PChar('已从云端下载原报上传的无锁文件到本地,但文件有错误,禁止导入!请致电纵横服务人员以获取帮助。'),
+          '警告', MB_OK + MB_ICONWARNING);
+        Exit;
+      end;
+    finally
+      vFileCheck.Free;
+    end;
+
+    {注意: 审核末通过的导入更新,这里的MD5码应取最终审核不通过项目的,否则会带来下载循环问题。
+    问题描述:
+    ①编制人运行软件,双击项目,发现审核不通过,自动下载无锁文件,开始新一期,保存关闭。
+    ②编制人再次运行软件,双击项目,MD5码不同,自动下载旧的审核不通过文件,覆盖本地。
+    ③编制人再次运行软件,双击项目,发现审核不通过,重复①,循环....
+    问:①那里下载无锁文件后不能改成新的MD5码吗?
+    答:不能,因为审核人的项目会变成无锁文件,看不到不通过项目。MD5码只能在上传后更新。
+    且编制人有个交互界面2种选择:a.下载更新不通过项目查看;b.下载更新无锁文件开始新一期。}
+    if not ImportFile(sLocalFile, FWebMD5_OnLine) then
+    begin
+      Application.MessageBox(PChar('已从云端下载原报上传的无锁文件到本地,但导入失败!请重试。'), '警告', MB_OK + MB_ICONWARNING);
+      Exit;
+    end;
+  end;
+
+  if FileExists(sLocalFile) then
+    DeleteFile(sLocalFile);
+
+  Result := True;
+end;
+
+// 为了跟PHP的数组兼容,这里限制数组的第一个元素是A[0](不能是A[1])
+procedure TProjectManagerFrame.OnLineChecker(AAr: TOVArr; var ABegin,
+  AEnd: Integer);
+var i, j, n: Integer;
+  vCS: TCheckStatus;
+begin
+  ABegin := 0;
+  AEnd := 0;
+  n := -1;
+
+  for i := 0 to High(AAr) do
+  begin
+    vCS := TCheckStatus(StrToInt(AAr[i, 5])-1);
+    if vCS = csChecking then
+    begin
+      n := i;  // 非常重要:传入的数组必须从第一个审核人到轮到工作中的那个人的前一个人
+      Break;
+    end;
+  end;
+
+  for i := n downto 0 do
+  begin
+    if AAr[i, 7] = '1' then             // 接口返回的第7列是线上审批标记
+    begin
+      AEnd := i + 1;
+      Break;
+    end
+    else
+      Break;
+  end;
+
+  if AEnd = 0 then Exit;
+
+  i := i - 1;
+  if i < 0 then
+  begin
+    ABegin := 1;
+    Exit;
+  end;
+
+
+  for j := i downto 0 do
+  begin
+    if AAr[j, 7] = '0' then
+    begin
+      ABegin := j + 2;
+      Break;
+    end
+    else
+    begin
+      if j = 0 then
+        ABegin := 1;
+    end;
+  end;
+end;
+
 end.