{*******************************************************************************
  单元名称：  CheckerFme.pas

  单元说明：  审核人窗口。

  作者时间：  Chenshilong, 2014-07-11
*******************************************************************************}

unit CheckerFme;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, OrderCheckerFme, JimLabels, Contnrs, Checker;

type
  TCheckerFrame = class(TFrame)
    pnlProject: TPanel;
    sbChecker: TScrollBox;
    pnlTitle: TPanel;
    labTitle: TJimGradLabel;
    tRefreshCheckers: TTimer;
    procedure tRefreshCheckersTimer(Sender: TObject);
  private
    FProjectData: TObject;
    FCount: Integer;
    FOwner: TObject;
    FOwnerFrame: TOrderCheckerFrame;
    FAddFrame: TOrderCheckerFrame;
    FList: TObjectList;          // Add窗也进FList
    FCurPos: Integer;
    procedure SetProjectData(const Value: TObject);
    procedure SetOwner(const Value: TObject);
    { Private declarations }
  public
    { Public declarations }
    property ProjectData: TObject read FProjectData write SetProjectData;
    property Owner: TObject read FOwner write SetOwner;
    property OwnerFrame: TOrderCheckerFrame read FOwnerFrame write FOwnerFrame;  // 这个特指终审人的Frame
    property AddFrame: TOrderCheckerFrame read FAddFrame write FAddFrame;        // 这个特指新增人的Frame
    property List: TObjectList read FList;
    property CurPos: Integer read FCurPos write FCurPos;

    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Init;
    // 审核人的名字、职位、公司、图像
    procedure AddNewChecker(AType: TCheckerFrameType; AID: Integer; AName,
      ARole, ACompany, AImagePath, ACheckerMemo: string; ACheckStatus: TCheckStatus;
      ACheckeTime: string; ACheckeOnLine: Integer);
    function InCheckerList(ACheckerID: Integer): Boolean;
    function HasNormalChecker: Boolean;        // 有普通审核人就返回True（光有业主不算）
    function HasChecker: Boolean;              // 列表不为空即返回True（光Add也算）
    procedure CheckerNameList(var ASL: TStringList);
    procedure RepairOrder;
    procedure RepairDelete(ACanDelete: Boolean);
    function FirstChecker: TOrderCheckerFrame;
    function NextChecker: TOrderCheckerFrame;
    function LastChecker: TOrderCheckerFrame;
    function Me: TOrderCheckerFrame;

    function CheckNo(ACheckStatus: TCheckStatus): Integer;                // 返回指定的审核状态是列表中的第几个人
  end;


implementation

uses FindUserFrm, PHPWebDm, ProjectData, CslJson, ConstUnit, ProjectFme;

{$R *.dfm}

procedure TCheckerFrame.AddNewChecker(AType: TCheckerFrameType; AID: Integer;
  AName, ARole, ACompany, AImagePath, ACheckerMemo: string; ACheckStatus: TCheckStatus;
  ACheckeTime: string; ACheckeOnLine: Integer);
var vChecker: TOrderCheckerFrame;
begin
  vChecker := TOrderCheckerFrame.Create(Self);
  vChecker.Owner := Self;
  vChecker.Init(AType, AID, AName, ARole, ACompany, AImagePath, ACheckerMemo, ACheckStatus, ACheckeTime, ACheckeOnLine);

  sbChecker.Height := sbChecker.Height + vChecker.Height;
  vChecker.Parent := sbChecker;
  vChecker.Top := FCurPos;
  FCurPos := FCurPos + vChecker.Height;
  vChecker.Align := alTop;

  // 调整位置
  case AType of
    cftChecker:
    begin
      vChecker.Name := 'OrderFrame' + IntToStr(AID);
      if Assigned(AddFrame) then       // 适用于查找审核人添加数据库后，插入Add窗之前
      begin
        vChecker.Top := AddFrame.Top;
        AddFrame.Top := vChecker.Top + vChecker.Height;
        OwnerFrame.Top := AddFrame.Top + AddFrame.Height;
        FList.Insert(FList.Indexof(AddFrame), vChecker);
      end
      else
        FList.Add(vChecker);
    end;
    cftOwner:      // 保险，保证终审窗一定在Add窗之后
    begin
      OwnerFrame := vChecker;
      vChecker.Name := 'OwnerFrame';
      if Assigned(AddFrame) then
        OwnerFrame.Top := AddFrame.Top + AddFrame.Height;
      FList.Add(vChecker);
    end;
    cftAdd:        // Add窗插入到终审窗之前
    begin
      AddFrame := vChecker;
      vChecker.Name := 'AddFrame';
      if Assigned(OwnerFrame) then
      begin
        AddFrame.Top := OwnerFrame.Top;
        OwnerFrame.Top := AddFrame.Top + AddFrame.Height;
        FList.Insert(FList.Indexof(OwnerFrame), vChecker);
      end
      else
        FList.Add(vChecker);
    end;
  end;
end;

procedure TCheckerFrame.Init;
var
  i, iIndex: Integer;
  vA: TOVArr;
  sURL, sPicPath, sID, sErrors: string;
  vProj: TProjectData;
  bOwner, bOwnerFinish: Boolean;
  vStatus: TCheckStatus;
  vCM: TChecker;
begin
  FList.Clear;
  OwnerFrame := nil;
  AddFrame := nil;
  sbChecker.Height := 0;
  FCurPos := 0;

  vProj := TProjectData(FProjectData);
  vProj.Checkers.Clear;
  
  // 这里，这里搞死爹...编制人第一期上报后，关掉项目，重新打开这个项目，第一次，
  // 我说的是第一次——一定读取不了审核人列表，但第二次、以后每次都正常。你知道
  // 读取不了这个列表的后果有多严重吗？网络版的每个角落都依赖于审核人的角色，所
  // 以后果就是直接崩溃，无法使用。查明原因：服务器那头的PHP第一次接收不了传上
  // 去的数据，日志显示读取到的数组为空。
  // 所以这里把参数移到URL中，通过URL的方式传递，避开用数组传递，问题解决。
  // 很明显，这种方式的局限性很大，只适合参数较少的情况。该问题已被珠海纵横公司
  // 计量支付网络版研发团队定性为PHP业界的灵异事件。如果哪天你用科学解释了它，请
  // 一定要告诉我个中缘由。chenshilong, 2014-07-21
  sURL := Format('%suser/get/all/%d/%d/measure', [PHPWeb.MeasureURL, vProj.WebID, vProj.PhaseIndex]);
  if PHPWeb.Search(sURL, [''], [''], vA) = 1 then
  begin
    for i := Low(vA) to High(vA) do
    begin
      sID := vA[i, 4];
      sPicPath := PHPWeb.UserPath + '1_' + sID + '.jpg';
      PHPWeb.DownFile(vA[i, 5], sPicPath);
      vStatus :=  TCheckStatus(StrToInt(vA[i, 3])-1);  // Json返回1、2、3、4
      bOwner := StrToInt(sID) = TProjectData(ProjectData).WebOwnerID;
      if bOwner then   // 添加业主
      begin
        if TProjectData(ProjectData).CurUserIsAuthor then
        begin
         {如果是编制人，添加业主前先添加Add框。
         数据库中，编制人没有审核人这样的状态。只有跟随标段的两种状态：
         ①有标段（顺便记录了编制人，标段是编制人创建的） ②没有标段。

         为什么不通过是否有标段来判断当前是否显示“添加新的审核人”呢？
         因为无法得知当前项目是数据库中已存在的最新一期还是仅存于本地尚末入库
         的最新一期。改由添加的位置给出提示}
         if (TProjectData(ProjectData).PhaseIndex > 0) and (not TProjectFrame(Owner).IsUped) then
           AddNewChecker(cftAdd, -1, '', '', '', '', '', csNotBegin, '', -1);
        end;

        AddNewChecker(cftOwner, StrToInt(sID),
          vA[i, 0], vA[i, 2], vA[i, 1], sPicPath, vA[i, 6], vStatus, vA[i, 8], StrToInt(vA[i, 7]));
      end
      else
        AddNewChecker(cftChecker, StrToInt(vA[i, 4]),
          vA[i, 0], vA[i, 2], vA[i, 1], sPicPath, vA[i, 6], vStatus, vA[i, 8], StrToInt(vA[i, 7]));

      vCM := TChecker.Create;
      iIndex := vProj.Checkers.Add(StrToInt(vA[i, 4]), vA[i, 0], vA[i, 2], vA[i, 6], vA[i, 8]);
      if vStatus in [csFinished, csNotPass] then
        vProj.Checkers.LastChecker := vProj.Checkers.Item[iIndex];
    end;
    RepairOrder;
  end
  else
  begin
    sErrors := Format('无法读取审批人列表，这将会导致桌面程序崩溃！%s地址：%s%s标段ID：%s，期号：%s',
      [#13#10#13#10, sURL, #13#10#13#10, IntToStr(vProj.WebID), IntToStr(vProj.PhaseIndex)]);
    Application.MessageBox(PChar(sErrors), '错误', MB_OK + MB_ICONERROR);
    Application.Terminate;
  end;
end;

procedure TCheckerFrame.SetProjectData(const Value: TObject);
begin
  FProjectData := Value;
end;

function TCheckerFrame.InCheckerList(ACheckerID: Integer): Boolean;
var i: Integer;
begin
  Result := False;
  for i := 0 to FList.Count - 1 do
  begin
    if TOrderCheckerFrame(FList[i]).UserID = ACheckerID then
    begin
      Result := True;
      Break;
    end;
  end;
end;

procedure TCheckerFrame.CheckerNameList(var ASL: TStringList);
var i: Integer;
  vFrame: TOrderCheckerFrame;
begin
  ASL.Clear;
  for i := 0 to FList.Count - 1 do
  begin
    vFrame := TOrderCheckerFrame(FList[i]);
    if vFrame.CheckerFrameType <> cftAdd then
      ASL.Add(Format('%s', [vFrame.UserName]));
  end;
end;

procedure TCheckerFrame.SetOwner(const Value: TObject);
begin
  FOwner := Value;
end;


procedure TCheckerFrame.RepairOrder;
var i: Integer;
begin
  for i := 0 to FList.Count - 1 do
    TOrderCheckerFrame(FList[i]).Order := i + 1;
end;

function TCheckerFrame.HasNormalChecker: Boolean;
var i: Integer;
begin
  Result := False;
  for i := 0 to FList.Count - 1 do
  begin
    if TOrderCheckerFrame(FList[i]).CheckerFrameType = cftChecker then
    begin
      Result := True;
      Break;
    end;
  end;
end;

constructor TCheckerFrame.Create(AOwner: TComponent);
begin
  inherited;
  FList := TObjectList.Create;
end;

destructor TCheckerFrame.Destroy;
begin
  FList.Free;
  inherited;
end;

function TCheckerFrame.FirstChecker: TOrderCheckerFrame;
begin
  Result := nil;
  if FList.Count > 0 then
  begin
    if TOrderCheckerFrame(FList[0]).CheckerFrameType <> cftAdd then
      Result := TOrderCheckerFrame(FList[0])
    else
      Result := TOrderCheckerFrame(FList[1]);
  end;
end;

function TCheckerFrame.NextChecker: TOrderCheckerFrame;
var i: Integer;
  vFrame: TOrderCheckerFrame;
begin
  Result := nil;
  if FList.Count = 0 then Exit;

  for i := 0 to FList.Count - 1 do
  begin
    if (TOrderCheckerFrame(FList[i]).UserID = PHPWeb.UserID) then
    begin
      if i = (FList.Count - 1) then Exit;     // 最后一个

      Result := TOrderCheckerFrame(FList[i + 1]);
      if Result.CheckerFrameType = cftAdd then
        Result := TOrderCheckerFrame(FList[i + 2]);

      Break;
    end;
  end;
end;

function TCheckerFrame.Me: TOrderCheckerFrame;
var i: Integer;
begin
  Result := nil;
  for i := 0 to FList.Count - 1 do
  begin
    if TOrderCheckerFrame(FList[i]).UserID = PHPWeb.UserID then
    begin
      Result := TOrderCheckerFrame(FList[i]);
      Break;
    end;
  end;
end;

procedure TCheckerFrame.RepairDelete(ACanDelete: Boolean);
var i: Integer;
begin
  for i := 0 to FList.Count - 1 do
  begin
    if (TOrderCheckerFrame(FList[i]) <> OwnerFrame) and
      (TOrderCheckerFrame(FList[i]) <> AddFrame) then
    begin
      TOrderCheckerFrame(FList[i]).lblOrderStatus.Visible := (not ACanDelete);
      TOrderCheckerFrame(FList[i]).btnDelete.Visible := ACanDelete;
    end;
  end;
end;

procedure TCheckerFrame.tRefreshCheckersTimer(Sender: TObject);
begin
  tRefreshCheckers.Enabled := False;
  try
    init;
    RepairDelete(True);
  except
    ShowMessage('删除成功，这里做了异常保护');
  end;
end;

function TCheckerFrame.HasChecker: Boolean;
begin
  Result := (FList.Count > 0);
end;

function TCheckerFrame.CheckNo(ACheckStatus: TCheckStatus): Integer;
var i, iCount: Integer;
begin
  Result := -1;
  
  for i := 0 to FList.Count - 1 do
  begin
    if TOrderCheckerFrame(FList[i]).CheckStatus = ACheckStatus then
    begin
      Result := i + 1;
      Break;
    end;
  end;
end;

function TCheckerFrame.LastChecker: TOrderCheckerFrame;
var i: Integer;
begin
  Result := FOwnerFrame;
end;

end.
