ProjectManagerFme.pas 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824
  1. unit ProjectManagerFme;
  2. interface
  3. uses
  4. ProjectManagerDm, ZhAPI,
  5. NewProjectFrm,
  6. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7. Dialogs, ZjGridDBA, ZJGrid, ComCtrls, ToolWin, ActnList,
  8. dxBar, sdGridDBA, sdGridTreeDBA, sdIDTree, CslJson, ExtCtrls,
  9. StdCtrls, sdDB, CslButton, OrderCheckerFme, Contnrs;
  10. type
  11. TStrArr = array of string;
  12. TProjectManagerFrame = class(TFrame)
  13. ToolBar: TToolBar;
  14. tobtnOpen: TToolButton;
  15. zgProjects: TZJGrid;
  16. tobtnDelete: TToolButton;
  17. ActionList1: TActionList;
  18. actnOpen: TAction;
  19. actnDelete: TAction;
  20. dxpmProjectManager: TdxBarPopupMenu;
  21. actnReceiveProject: TAction;
  22. stdProjects: TsdGridTreeDBA;
  23. actnNewProject: TAction;
  24. actnNewSubProject: TAction;
  25. actnNewTender: TAction;
  26. pnlTenderProperty: TPanel;
  27. sdTenderProperty: TsdGridDBA;
  28. sprProperty: TSplitter;
  29. tobtnRenane: TToolButton;
  30. actnRename: TAction;
  31. tobtnImport: TToolButton;
  32. tobtnExport: TToolButton;
  33. actnImport: TAction;
  34. actnExport: TAction;
  35. tobtn1: TToolButton;
  36. pnlWeb: TPanel;
  37. pnlProject: TPanel;
  38. shp2: TShape;
  39. shp1: TShape;
  40. shp3: TShape;
  41. shp4: TShape;
  42. pnlTenderTitle: TPanel;
  43. lblBidName: TLabel;
  44. pnlShadow: TPanel;
  45. pnlProgress: TPanel;
  46. lblPeriodTotal: TLabel;
  47. lblPeriodState: TLabel;
  48. lblProgress: TLabel;
  49. lblPeriod: TLabel;
  50. pnlBelongProject: TPanel;
  51. lblBelongProject: TLabel;
  52. lblProjName: TLabel;
  53. lblLeftHalfBracket: TLabel;
  54. lblOnwerCompany: TLabel;
  55. lblOnwerName: TLabel;
  56. pnlProjectType: TPanel;
  57. lblProjectType: TLabel;
  58. lblWebProjCtgyName: TLabel;
  59. zgTenderProperty: TZJGrid;
  60. actnOpenBackupFolder: TAction;
  61. sbChecker: TScrollBox;
  62. procedure actnOpenExecute(Sender: TObject);
  63. procedure actnDeleteExecute(Sender: TObject);
  64. procedure zgProjectsMouseDown(Sender: TObject; Button: TMouseButton;
  65. Shift: TShiftState; X, Y: Integer);
  66. procedure actnReceiveProjectExecute(Sender: TObject);
  67. procedure actnNewProjectExecute(Sender: TObject);
  68. procedure actnNewSubProjectExecute(Sender: TObject);
  69. procedure actnNewTenderExecute(Sender: TObject);
  70. procedure zgProjectsDrawCellText(ACanvas: TCanvas; const ARect: TRect;
  71. const ACoord: TPoint; AGrid: TZJGrid; const Text: String;
  72. var ADefaultDraw: Boolean);
  73. procedure actnNewSubProjectUpdate(Sender: TObject);
  74. procedure actnNewTenderUpdate(Sender: TObject);
  75. procedure zgProjectsCurrentChanged(Sender: TObject; Col, Row: Integer);
  76. procedure actnSubmitProjectUpdate(Sender: TObject);
  77. procedure actnReplyProjectUpdate(Sender: TObject);
  78. procedure actnRenameExecute(Sender: TObject);
  79. procedure actnOpenUpdate(Sender: TObject);
  80. procedure actnImportExecute(Sender: TObject);
  81. procedure actnExportExecute(Sender: TObject);
  82. procedure actnDeleteUpdate(Sender: TObject);
  83. procedure actnOpenBackupFolderExecute(Sender: TObject);
  84. procedure actnRenameUpdate(Sender: TObject);
  85. procedure zgProjectsShowHint(var HintStr: String; var CanShow: Boolean;
  86. var HintInfo: THintInfo; const ACoord: TPoint);
  87. procedure actnExportUpdate(Sender: TObject);
  88. procedure actnOpenBackupFolderUpdate(Sender: TObject);
  89. private
  90. FProjectManagerData: TProjectManagerData;
  91. // Chenshilong,2016.03.24
  92. // 这部分线上和本地一致,无需区分
  93. FID: Integer; // 本地标段文件ID
  94. FWebID: Integer; // 关联服务器用的ID(服务器有自己的ID体系)
  95. FWebAuthorID: Integer; // 编制人
  96. FWebOwnerID: Integer; // 业主
  97. // 本地存储值、线上存储值。线上修改后,需要同步到本地
  98. FWebMD5_Local: string; // 本地存储的MD5
  99. FWebMD5_OnLine: string; // 线上存储的最新的MD5(下同)
  100. FWebBidName_Local: string; // 标段名 (当无法同线上取得联系时,本地需要用到该名称来提示)
  101. FWebBidName_OnLine: string;
  102. FWebFolder_OnLine: string; // 这个命名不妥,但很直观。线上的项目名称、项目类型概念跟本地颠倒,很混乱。
  103. FWebSubFolder_OnLine: string;
  104. FWebOwnerCompany: string;
  105. FWebOwnerRole: string;
  106. FWebOwnerName: string;
  107. FWebCheckStatusMy: TCheckStatus; // 登陆用户在当前项目中的工作状态。
  108. FWebCheckStatusProject: TCheckStatus; // 项目的审核状态。
  109. FOnLineCheckerBegin: Integer; // 线上审批的起始人。 010110111 起7止9。 0101101110 起0止0。
  110. FOnLineCheckerEnd: Integer; // 线上审批的截止人。
  111. FOnLineCheckerEndIsOwner: Boolean; // 终审是线上审批
  112. FPhaseTotal: Integer;
  113. FPhaseNo: Integer;
  114. FCurPos: Integer; // 用来控制审核人的添加位置
  115. FCheckerList: TObjectList;
  116. function ReceiveFile(const AFileName: string; AIsReback: Boolean = False): Boolean;
  117. function ImportFile(const AFileName: string; AFileMD5: string = ''): Boolean;
  118. procedure ConnectButtonWithAction;
  119. function GetImportProjectName(const AFileName: string; AParent: TsdIDTreeNode): string;
  120. function IsProject(ANode: TsdIDTreeNode): Boolean;
  121. function IsLeafProject(ANode: TsdIDTreeNode): Boolean;
  122. function IsUnEmptyLeafProject(ANode: TsdIDTreeNode): Boolean;
  123. function CheckOpened(ANode: TsdIDTreeNode): Boolean;
  124. procedure SetPropertyVisible(AVisible: Boolean);
  125. procedure ShowProjectInfoTopAndCheckers;
  126. // 网络上的目录结构,本地有则定位,没有则创建。
  127. procedure CheckWebFolders(AFolderID, ASubFolderID: Integer;
  128. AFolderName, ASubFolderName: string);
  129. // ANewBidName: 项目的最新标段名(取自服务器,有人改名了,本地的就变成旧的)
  130. procedure CheckBidName(AID: Integer; ANewBidName: string); overload;
  131. procedure CheckBidName(AUserID, AWebID: Integer; ANewBidName: string); overload;
  132. procedure ClearLocalValues;
  133. procedure GetLocalValues(ARec: TsdDataRecord); overload;
  134. // 用户ID、网络标段ID、Type=1可以定位一个标段。
  135. procedure GetLocalValues(AUserID, AWebID: Integer); overload;
  136. // 1 等待我审核的标段文件; 2 我参与的全部标段文件
  137. procedure DoBatchReceiveOnline(ARequestType: Integer);
  138. function LocalMD5(AUserID, AWebID: Integer): string;
  139. procedure BubbleSortProjects;
  140. // AReceiveKind: 1 接收; 2 导入
  141. function FileDownAndReceive(ADownURL: string; AReceiveKind: Integer): Boolean;
  142. // 线上审批的起止人
  143. procedure OnLineChecker(AAr: TOVArr; var ABegin, AEnd: Integer; var AOnLineEndIsOwner: Boolean);
  144. public
  145. constructor Create(AOwner: TComponent); override;
  146. destructor Destroy; override;
  147. procedure DoBatchReceiveAllOnline;
  148. // AType: -2 繁忙; -1 正常读取; 0 第0期; 1 第1期。
  149. procedure ShowProjectInfoTop(AType: Integer = -1);
  150. function Rec(AProjectID: Integer): TsdDataRecord;
  151. function CurRec: TsdDataRecord;
  152. function CurRecAttachmentPath: string;
  153. function AttachmentFileCountsWithoutManageFile(ANode: TsdIDTreeNode): Integer;
  154. property ProjectCheckStatus: TCheckStatus read FWebCheckStatusProject;
  155. end;
  156. implementation
  157. uses
  158. MainFrm, UtilMethods, ProjectCommands, Globals, ConfigDoc, ConstUnit,
  159. WebNewTenderFrm, PHPWebDm, Math, mProgressFrm, ProgressHintFrm,
  160. ShellAPI, ProjectFme;
  161. {$R *.dfm}
  162. procedure TProjectManagerFrame.ConnectButtonWithAction;
  163. begin
  164. SetDxBtnAction(actnNewProject, MainForm.dxbtnNewProject);
  165. SetDxBtnAction(actnNewSubProject, MainForm.dxbtnNewSubProject);
  166. SetDxBtnAction(actnNewTender, MainForm.dxbtnNewTender);
  167. SetDxBtnAction(actnOpen, MainForm.dxbtnOpenProject);
  168. SetDxBtnAction(actnDelete, MainForm.dxbtnDeleteProject);
  169. SetDxBtnAction(actnReceiveProject, MainForm.dxbtnReceiveProject);
  170. SetDxBtnAction(actnOpenBackupFolder, MainForm.dxbtnOpenBackupFolder);
  171. SetDxBtnAction(actnRename, MainForm.dxbtnRename);
  172. end;
  173. constructor TProjectManagerFrame.Create(AOwner: TComponent);
  174. begin
  175. inherited;
  176. FCheckerList := TObjectList.Create;
  177. FProjectManagerData := ProjectManager;
  178. FProjectManagerData.Open;
  179. stdProjects.IDTree := FProjectManagerData.ProjectsTree;
  180. sdTenderProperty.DataView := FProjectManagerData.sdvTenderProperty;
  181. ConnectButtonWithAction;
  182. SetPropertyVisible(False);
  183. sbChecker.Height := 0;
  184. if G_IsCloud then
  185. begin
  186. Application.HintPause := 200;
  187. Application.HintHidePause := 60000;
  188. tobtnImport.Visible := False;
  189. stdProjects.TreeOptions := stdProjects.TreeOptions - [aoAllowUpLevel, aoAllowDownLevel];
  190. stdProjects.Options := stdProjects.Options - [aoAllowUpMove, aoAllowDownMove];
  191. CreateProgress('正在从云端下载新项目');
  192. try
  193. actnReceiveProject.Execute;
  194. finally
  195. CloseProgress;
  196. end;
  197. end;
  198. end;
  199. function SearchFileOnline(AURL: string; var ADownURL, AFolder, ASubFolder, ABidName, AMD5Web, AError: string;
  200. var AFolderID, ASubFolderID: Integer): Integer;
  201. var vArr: TOVArr;
  202. begin
  203. Result := PHPWeb.Search(AURL, [''], [''], vArr);
  204. AError := '';
  205. if Result = 1 then
  206. begin
  207. if High(vArr) >= 0 then
  208. begin
  209. ADownURL := vArr[0, 0];
  210. AFolder := vArr[0, 2];
  211. ASubFolder := vArr[0, 3];
  212. AMD5Web := vArr[0, 1];
  213. AFolderID := StrToInt(vArr[0, 4]);
  214. ASubFolderID := StrToInt(vArr[0, 5]);
  215. ABidName := vArr[0, 6];
  216. end
  217. else
  218. Result := 10; // 返回10,表示无记录。用这个数字代表是否觉得怪异?没办法,0被占用了。
  219. end
  220. else if Result = 0 then
  221. AError := PHPWeb.PageError('标段更新数据失败')
  222. else if Result = -1 then
  223. AError := PHPWeb.NetError('标段更新数据失败');
  224. end;
  225. // 双击打开项目 TagB
  226. procedure TProjectManagerFrame.actnOpenExecute(Sender: TObject);
  227. var
  228. vSel: TsdIDTreeNode;
  229. vRec: TsdDataRecord;
  230. sHint: string;
  231. function CanOpen: Boolean;
  232. var
  233. sSearchURL, sDownURL,
  234. sMD5_UnLock, sError, sLocalFile: string;
  235. iSearch, iFolderID, iSubFolderID: Integer;
  236. bLock, bCanImp: Boolean;
  237. vFileCheck: TTenderFileChecker;
  238. begin
  239. Result := False;
  240. // 先按正常接口找到最新的MD5码看是否需要更新
  241. sSearchURL := Format('%stender/get/%d/update', [PHPWeb.MeasureURL, FWebID]);
  242. iSearch := SearchFileOnline(sSearchURL, sDownURL, FWebFolder_OnLine, FWebSubFolder_OnLine, FWebBidName_OnLine, FWebMD5_OnLine, sError, iFolderID, iSubFolderID);
  243. if iSearch = 1 then
  244. begin
  245. try
  246. CheckWebFolders(iFolderID, iSubFolderID, FWebFolder_OnLine, FWebSubFolder_OnLine);
  247. CheckBidName(FID, FWebBidName_OnLine);
  248. finally
  249. if vSel <> nil then
  250. vSel.LocateInControl;
  251. end;
  252. // 打开前一定要先下载最新的标段文件(无论审核有没有通过)
  253. if FWebMD5_OnLine <> FWebMD5_Local then
  254. if not FileDownAndReceive(sDownURL, 1) then Exit;
  255. // 编制人且项目末通过
  256. if (FWebAuthorID = PHPWeb.UserID) and (FWebCheckStatusProject = csNotPass) then
  257. begin
  258. sHint := '本期计量审批不通过,你现在可以:' + #10#13 + '点击【是(Y)】重新开始本期计量,软件将打开本期上报时的数据,开始重新计量;' +
  259. #10#13 +'点击【否(N)】查看不通过计量,软件将打开本期最后审批的数据,重新打开标段' + '可再次打开本确认窗口。';
  260. if Application.MessageBox(PChar(sHint), '询问', MB_YESNO + MB_ICONQUESTION) = ID_Yes then
  261. begin
  262. sSearchURL := Format('%suser/create/%d/%d/new/audit', [PHPWeb.MeasureURL, FWebID, FPhaseNo]);
  263. case SearchFileOnline(sSearchURL, sDownURL, FWebFolder_OnLine, FWebSubFolder_OnLine, FWebBidName_OnLine, sMD5_UnLock, sError, iFolderID, iSubFolderID) of
  264. 1:
  265. begin
  266. if not FileDownAndReceive(sDownURL, 2) then Exit;
  267. sHint := '【重要提示】:本期计量已重新开始,在本次上报完成前,请勿删除该标段或更换电脑。';
  268. Application.MessageBox(PChar(sHint), '提示', MB_OK + MB_ICONINFORMATION);
  269. end;
  270. 0, -1:
  271. begin
  272. sHint := sError + '(因网络出错,无法连接到云端以获取本期原报上传的无锁文件,无法重新开始本期,本次操作已取消。请重试。';
  273. Application.MessageBox(PChar(sHint), '警告', MB_OK + MB_ICONWARNING);
  274. Exit;
  275. end;
  276. end;
  277. end;
  278. end;
  279. end
  280. else if (iSearch = 10) then
  281. begin
  282. if not PHPWeb.ExistInServer(FWebID) then
  283. begin
  284. sHint :='该项目[' + FWebBidName_Local + ']在云端已被删除,点击"确定"后,可手动删除该项目。';
  285. Application.MessageBox(PChar(sHint), '提示', MB_OK + MB_ICONINFORMATION);
  286. Exit;
  287. end;
  288. end
  289. else if (iSearch = 0) or (iSearch = -1) then
  290. begin
  291. sHint := sError + '(因网络出错,无法检测[' + FWebBidName_Local + ']在云端是否有更新,本次操作已取消,请重试)。';
  292. Application.MessageBox(PChar(sHint), '警告', MB_OK + MB_ICONWARNING);
  293. Exit;
  294. end;
  295. Result := True;
  296. end;
  297. var
  298. CurProjectFme: TProjectFrame;
  299. begin
  300. // 打开前先下载更新
  301. Screen.Cursor := crHourGlass;
  302. try
  303. vSel := stdProjects.IDTree.Selected;
  304. vRec := vSel.Rec;
  305. if G_IsCloud then
  306. begin
  307. GetLocalValues(CurRec);
  308. // 以下这段已经包含在MainForm.OpenProject(vRec)中了,但在调用这句之前,网络版要提前用一下。
  309. if MainForm.HasOpened(FID) then
  310. begin
  311. MainForm.LocateProject(FID);
  312. Exit;
  313. end;
  314. if not CanOpen then
  315. Exit;
  316. end;
  317. CurProjectFme := MainForm.OpenProject(vRec);
  318. if G_IsCloud then
  319. begin
  320. // 云版,如果用户在打开项目的过程中,切换界面回项目管理,MainFrom.CurProjectFrame值为nil,后面的调用,包括MainForm.actnCloseProject.Execute都会出错
  321. // 其中由于前面调用的MainForm.LocateProject触发的一系列事件中,调用到了SetPropertyVisible,其中执行了Screen.Cursor := crDefault
  322. // 导致鼠标状态还原,用户可以点击,单机版下测试,属性状态为crHourGlass时,亦可以切换会项目管理
  323. // 按逻辑,CheckFileAndCloudCheckerList这种方法不应在界面,应在控制器,亦不可直接调用MainForm.actnCloseProject.Execute
  324. // 怕按逻辑改动引起更多Bug,故继续错下去,检查MainForm.CurProjectFrame是否正确,并再次禁用鼠标
  325. if CurProjectFme <> MainForm.CurProjectFrame then
  326. begin
  327. Screen.Cursor := crHourGlass;
  328. MainForm.LocateProject(CurProjectFme.ProjectData.ProjectID);
  329. end;
  330. if not MainForm.CurProjectFrame.CheckFileAndCloudChekerList then
  331. begin
  332. sHint := '项目校验:“' + FWebBidName_OnLine + '”文件中的审核人和云端的审核人不一致,' +
  333. '禁止继续操作,项目即将关闭!请删除本地项目重新从云端获取,' +
  334. '重新获取后如果仍然存在同样的问题,请联系纵横服务人员以寻求帮助。';
  335. Application.MessageBox(PChar(sHint), '文件错误', MB_OK +MB_ICONWARNING);
  336. MainForm.actnCloseProject.Execute;
  337. Exit;
  338. end;
  339. end;
  340. finally
  341. Screen.Cursor := crDefault;
  342. end;
  343. end;
  344. procedure TProjectManagerFrame.actnDeleteExecute(Sender: TObject);
  345. begin
  346. if stdProjects.IDTree.Count = 0 then Exit;
  347. with stdProjects.IDTree.Selected.Rec do
  348. if QuestMessage(Format('确定要删除[%s]吗?', [ValueByName('Name').AsString])) then
  349. begin
  350. Screen.Cursor := crHourGlass;
  351. try
  352. FProjectManagerData.Delete;
  353. finally
  354. Screen.Cursor := crDefault;
  355. end;
  356. end;
  357. end;
  358. procedure TProjectManagerFrame.zgProjectsMouseDown(Sender: TObject;
  359. Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  360. begin
  361. if Button = mbRight then
  362. dxpmProjectManager.PopupFromCursorPos
  363. else if (zgProjects.CurCol = 1) and (Button = mbLeft) and (ssDouble in Shift)
  364. and Assigned(stdProjects.IDTree.Selected) then
  365. begin
  366. if IsProject(stdProjects.IDTree.Selected) then
  367. stdProjects.IDTree.Selected.Expand
  368. else
  369. actnOpen.Execute;
  370. end;
  371. end;
  372. function TProjectManagerFrame.ReceiveFile(const AFileName: string; AIsReback: Boolean): Boolean;
  373. var
  374. vRP: TReceiveProject;
  375. vNode: TsdIDTreeNode;
  376. begin
  377. Result := False;
  378. vRP := TReceiveProject.Create(stdProjects.IDTree.Selected);
  379. try
  380. ProjectManager.RefreshSeedID;
  381. if G_IsCloud then
  382. begin
  383. vRP.IsReback := AIsReback;
  384. vRP.Lock := (FWebAuthorID = PHPWeb.UserID) or
  385. ((FWebAuthorID <> PHPWeb.UserID) and (FWebCheckStatusMy <> csChecking));
  386. vNode := vRP.ReceiveForLost(AFileName, FOnLineCheckerBegin, FOnLineCheckerEnd, FOnLineCheckerEndIsOwner);
  387. if vNode <> nil then
  388. begin
  389. vNode.Rec.BeginUpdate;
  390. vNode.Rec.ValueByName('WebMD5').AsString := FWebMD5_OnLine;
  391. vNode.Rec.ValueByName('WebUserID').AsInteger := PHPWeb.UserID;
  392. vNode.Rec.EndUpdate;
  393. end;
  394. end
  395. else
  396. vNode := vRP.Receive(AFileName);
  397. finally
  398. case vRP.MessageID of
  399. 0: begin
  400. Result := True;
  401. vNode.LocateInControl;
  402. end;
  403. 1: ErrorMessage('当前标段处于打开状态,未能成功接收,请先关闭标段再次接收。');
  404. 2: ErrorMessage('下载数据与审核状态不一致,未能成功接收,请再次接收。');
  405. 3: ErrorMessage('升级数据失败,未能成功接收,请再次接收。');
  406. end;
  407. vRP.Free;
  408. FProjectManagerData.Save;
  409. end;
  410. end;
  411. // 登录后自动扫描等待我审核的项目 TagC
  412. procedure TProjectManagerFrame.actnReceiveProjectExecute(Sender: TObject);
  413. procedure DoReceiveLocal;
  414. var
  415. sFileName: string;
  416. begin
  417. if SelectFile(sFileName, '.rmf;*.arf') then
  418. begin
  419. ShowProgressHint('正在接收项目并升级数据');
  420. try
  421. ReceiveFile(sFileName);
  422. finally
  423. CloseProgressHint;
  424. end;
  425. end;
  426. end;
  427. var OnCC: TZjCellNotifyEvent;
  428. begin
  429. Screen.Cursor := crHourGlass;
  430. try
  431. if G_IsCloud then
  432. begin
  433. OnCC := zgProjects.OnCurrentChanged;
  434. try
  435. zgProjects.OnCurrentChanged := nil;
  436. DoBatchReceiveOnline(1);
  437. if stdProjects.IDTree.FirstNode <> nil then
  438. stdProjects.IDTree.FirstNode.LocateInControl;
  439. finally
  440. zgProjects.OnCurrentChanged := OnCC;
  441. end;
  442. end
  443. else
  444. DoReceiveLocal;
  445. finally
  446. Screen.Cursor := crDefault;
  447. end;
  448. end;
  449. function TProjectManagerFrame.GetImportProjectName(
  450. const AFileName: string; AParent: TsdIDTreeNode): string;
  451. begin
  452. Result := ExtractSimpleFileName(AFileName);
  453. while FProjectManagerData.ExistProject(Result, AParent) do
  454. if not InputNewProjectName(Result, '导入', AParent) then Abort;
  455. end;
  456. procedure TProjectManagerFrame.actnNewProjectExecute(Sender: TObject);
  457. var
  458. sName: string;
  459. begin
  460. if G_IsCloud then Exit; // 云版线上与本地要保持同步,不允许本地新建
  461. if InputNewProjectName(sName, '新建', stdProjects.IDTree.Selected) then
  462. FProjectManagerData.InsertProject(sName, stdProjects.IDTree.Selected);
  463. end;
  464. procedure TProjectManagerFrame.actnNewSubProjectExecute(Sender: TObject);
  465. var
  466. sName: string;
  467. begin
  468. if G_IsCloud then Exit;
  469. if InputNewProjectName(sName, '新建', stdProjects.IDTree.Selected) then
  470. FProjectManagerData.InsertSubProject(sName, stdProjects.IDTree.Selected);
  471. end;
  472. procedure TProjectManagerFrame.actnNewTenderExecute(Sender: TObject);
  473. function AddAndOpenTender(const ATenderName: string): TsdIDTreeNode;
  474. begin
  475. Result := FProjectManagerData.InsertTender(ATenderName, stdProjects.IDTree.Selected);
  476. MainForm.OpenProject(Result.Rec);
  477. end;
  478. // 网络版新建标段 TagD
  479. procedure NewProjectWithOnline;
  480. var
  481. WebNewTenderForm: TWebNewTenderForm;
  482. sName, sKey, sURL: string;
  483. stnNew: TsdIDTreeNode;
  484. iID, iFolderID, iSubFolderID: Integer;
  485. vRec: TsdDataRecord;
  486. vArr: array of string;
  487. begin
  488. WebNewTenderForm := TWebNewTenderForm.Create(nil);
  489. try
  490. WebNewTenderForm.ShowModal;
  491. if WebNewTenderForm.ModalResult = mrOK then
  492. begin
  493. sKey := WebNewTenderForm.edtKey.Text;
  494. sName := WebNewTenderForm.edtTenderName.Text;
  495. // 同服务器取得联系
  496. iID := -1;
  497. vArr := VarArrayOf(['catid', 'name', 'company', 'phone', 'mobile', 'qq',
  498. 'pname', 'ptype', 'jobs', 'avatar', 'ownuid', 'pnameid', 'ptypeid']);
  499. sURL := Format('%s%d/%s/%s/creatmeasure', [PHPWeb.MeasureURL, PHPWeb.UserID, sName, sKey]); // AnsiToUtf8(sName)
  500. case PHPWeb.Search(sURL, [], [], vArr) of
  501. 1:
  502. begin
  503. iID := StrToInt(vArr[0]);
  504. iFolderID := StrToInt(vArr[11]);
  505. iSubFolderID := StrToInt(vArr[12]);
  506. CheckWebFolders(iFolderID, iSubFolderID, vArr[6], vArr[7]);
  507. end;
  508. 0:
  509. begin
  510. Application.MessageBox(PChar(PHPWeb.PageError('创建标段失败' + '[' + vArr[0] + ']')),
  511. '警告', MB_OK + MB_ICONWARNING);
  512. Exit;
  513. end;
  514. -1:
  515. begin
  516. Application.MessageBox(PChar(PHPWeb.NetError('创建标段失败')),
  517. '警告', MB_OK + MB_ICONWARNING);
  518. Exit;
  519. end;
  520. end;
  521. // 本地创建
  522. stnNew := FProjectManagerData.InsertTender(sName, stdProjects.IDTree.Selected);
  523. // 这里把Web获取的信息存储到项目管理里面。
  524. vRec := stnNew.Rec;
  525. vRec.BeginUpdate;
  526. vRec.ValueByName('WebID').AsInteger := iID;
  527. vRec.ValueByName('WebOwnerID').AsInteger := StrToInt(vArr[10]); // 业主
  528. vRec.ValueByName('WebAuthorID').AsInteger := PHPWeb.UserID; // 编制人
  529. vRec.ValueByName('WebUserID').AsInteger := PHPWeb.UserID; // 当前用户,用于只显示自己的项目
  530. vRec.ValueByName('WebKey').AsString := sKey;
  531. vRec.EndUpdate;
  532. GetLocalValues(vRec);
  533. FWebOwnerName := vArr[1];
  534. FWebOwnerCompany := vArr[2];
  535. FWebOwnerRole := vArr[8];
  536. FWebFolder_OnLine := vArr[6];
  537. FWebSubFolder_OnLine := vArr[7];
  538. // WebOwnerImage := vArr[9];
  539. // WebOwnerPhone := vArr[3];
  540. // WebOwnerMobile := vArr[4];
  541. // WebOwnerQQ := vArr[5];
  542. ShowProjectInfoTop(0);
  543. FProjectManagerData.Save;
  544. MainForm.OpenProject(vRec);
  545. end;
  546. finally
  547. WebNewTenderForm.Free;
  548. end;
  549. end;
  550. procedure NewProject;
  551. var
  552. sName: string;
  553. begin
  554. if InputNewProjectName(sName, '新建', stdProjects.IDTree.Selected) then
  555. AddAndOpenTender(sName);
  556. end;
  557. begin
  558. if G_IsCloud then
  559. NewProjectWithOnline
  560. else
  561. NewProject;
  562. end;
  563. procedure TProjectManagerFrame.zgProjectsDrawCellText(ACanvas: TCanvas;
  564. const ARect: TRect; const ACoord: TPoint; AGrid: TZJGrid;
  565. const Text: String; var ADefaultDraw: Boolean);
  566. procedure GetBitmap(AImage: TBitmap; ANode: TsdIDTreeNode);
  567. begin
  568. if Assigned(ANode) and Assigned(ANode.Rec) then
  569. begin
  570. if ANode.Rec.ValueByName('Type').AsInteger = 0 then
  571. if ANode.Expanded and ANode.HasChildren then
  572. MainForm.Images.GetBitmap(34, AImage)
  573. else
  574. MainForm.Images.GetBitmap(34, AImage)
  575. else
  576. MainForm.Images.GetBitmap(11, AImage);
  577. end
  578. else
  579. AImage := nil;
  580. end;
  581. const
  582. rIconWidth = 16;
  583. rIconHeight = 16;
  584. var
  585. Img: TBitmap;
  586. Cell: TZjCell;
  587. rImg: TRect;
  588. vNode: TsdIDTreeNode;
  589. begin
  590. if (ACoord.X = 1) and (ACoord.Y > zgProjects.FixedRowCount - 1) then
  591. begin
  592. Cell := zgProjects.Cells[ACoord.X, ACoord.Y];
  593. Img := TBitmap.Create;
  594. try
  595. vNode := stdProjects.IDTree.Items[ACoord.Y-zgProjects.FixedRowCount];
  596. GetBitmap(Img, vNode);
  597. case Cell.Align of
  598. gaTopLeft, gaTopCenter, gaTopRight:
  599. rImg := Rect(ARect.Left + 2, ARect.Top, ARect.Left + rIconWidth, ARect.Top + rIconHeight);
  600. gaCenterLeft, gaCenterCenter, gaCenterRight:
  601. rImg := Rect(ARect.Left + 2, ARect.Top + (ARect.Bottom - ARect.Top - rIconHeight) div 2, ARect.Left + rIconWidth, ARect.Bottom - (ARect.Bottom - ARect.Top - rIconHeight) div 2);
  602. gaBottomLeft, gaBottomCenter, gaBottomRight:
  603. rImg := Rect(ARect.Left + 2, ARect.Bottom - rIconHeight, ARect.Left + rIconWidth, ARect.Bottom);
  604. end;
  605. ACanvas.StretchDraw(rImg, Img);
  606. WriteText(ACanvas, Rect(ARect.Left + rIconWidth, ARect.Top, ARect.Right, ARect.Bottom)
  607. , 2, 2, Text, Cell.Align, False);
  608. ADefaultDraw := False;
  609. finally
  610. Img.Free;
  611. end;
  612. end;
  613. end;
  614. procedure TProjectManagerFrame.actnNewSubProjectUpdate(Sender: TObject);
  615. begin
  616. TAction(Sender).Enabled := Assigned(stdProjects.IDTree.Selected)
  617. and IsProject(stdProjects.IDTree.Selected)
  618. and (not IsUnEmptyLeafProject(stdProjects.IDTree.Selected));
  619. end;
  620. procedure TProjectManagerFrame.actnNewTenderUpdate(Sender: TObject);
  621. var bCloud: Boolean;
  622. vNode: TsdIDTreeNode;
  623. begin
  624. bCloud := G_IsCloud;
  625. // 只有编制人才能创建新标段?逻辑先后有问题:编制人是在创建标段之后产生的。
  626. // 创建前,当前用户只是一个帐户,它是不是编制人末知,因为它还可以是其它角色。
  627. // 同一帐户在不同的标段可以作为不同的角色。
  628. if bCloud then
  629. begin
  630. TAction(Sender).Enabled := True;
  631. end
  632. else
  633. begin
  634. vNode := stdProjects.IDTree.Selected;
  635. TAction(Sender).Enabled := Assigned(vNode) and IsProject(vNode) and IsLeafProject(vNode);
  636. end;
  637. end;
  638. function TProjectManagerFrame.IsLeafProject(ANode: TsdIDTreeNode): Boolean;
  639. begin
  640. if ANode.HasChildren then
  641. Result := ANode.FirstChild.Rec.ValueByName('Type').AsInteger = 1
  642. else
  643. Result := ANode.Rec.ValueByName('Type').AsInteger = 0;
  644. end;
  645. function TProjectManagerFrame.IsProject(ANode: TsdIDTreeNode): Boolean;
  646. begin
  647. Result := ANode.Rec.ValueByName('Type').AsInteger = 0;
  648. end;
  649. function TProjectManagerFrame.IsUnEmptyLeafProject(
  650. ANode: TsdIDTreeNode): Boolean;
  651. begin
  652. Result := ANode.HasChildren and (ANode.Rec.ValueByName('Type').AsInteger = 1);
  653. end;
  654. procedure TProjectManagerFrame.SetPropertyVisible(AVisible: Boolean);
  655. begin
  656. // 单击刷新项目信息 TagA
  657. if G_IsCloud then
  658. begin
  659. if CurRec = nil then Exit;
  660. pnlTenderProperty.Visible := False;
  661. pnlWeb.Visible := AVisible;
  662. if AVisible then
  663. begin
  664. CreateProgress('云端读取项目信息');
  665. try
  666. ShowProjectInfoTopAndCheckers;
  667. finally
  668. CloseProgress;
  669. end;
  670. end;
  671. end
  672. else
  673. begin
  674. pnlWeb.Visible := False;
  675. pnlTenderProperty.Visible := AVisible;
  676. sprProperty.Visible := AVisible;
  677. end;
  678. end;
  679. procedure TProjectManagerFrame.zgProjectsCurrentChanged(Sender: TObject;
  680. Col, Row: Integer);
  681. begin
  682. if G_IsCloud then
  683. begin
  684. if CurRec <> nil then
  685. begin
  686. // 加这句后产生Bug:上报项目后,记录不曾移动,FID不变,不会刷新
  687. // if FID <> CurRec.ValueByName('ID').AsInteger then
  688. SetPropertyVisible(CurRec.ValueByName('Type').AsInteger = 1);
  689. // OnCurrentChanged取得的 CurRec.ValueByName() 值并不总是可靠,这里加保险。
  690. // 如调用locateInControl后,执行到这里取得的CurRec.ValueByName('ID')值还是上一条的。
  691. if (CurRec.ValueByName('Type').AsInteger = 1) and (not pnlWeb.Visible) then
  692. pnlWeb.Visible := True;
  693. end;
  694. end;
  695. end;
  696. procedure TProjectManagerFrame.actnSubmitProjectUpdate(Sender: TObject);
  697. begin
  698. TAction(Sender).Enabled := Assigned(stdProjects.IDTree.Selected)
  699. and (stdProjects.IDTree.Selected.Rec.ValueByName('Type').AsInteger = 1)
  700. and (stdProjects.IDTree.Selected.Rec.ValueByName('AuditStatus').AsInteger < iMaxStageCount-1);
  701. end;
  702. procedure TProjectManagerFrame.actnReplyProjectUpdate(Sender: TObject);
  703. begin
  704. TAction(Sender).Enabled := Assigned(stdProjects.IDTree.Selected)
  705. and (stdProjects.IDTree.Selected.Rec.ValueByName('Type').AsInteger = 1);
  706. end;
  707. procedure TProjectManagerFrame.actnRenameExecute(Sender: TObject);
  708. function CanRename(ARec: TsdDataRecord; const ANewName: string): Boolean;
  709. var
  710. sURL: string;
  711. iRename: Integer;
  712. vArr: array [0..0] of string;
  713. begin
  714. Result := True;
  715. if not G_IsCloud then Exit;
  716. // 云版 重命名须确保同步服务器
  717. sURL := Format('%stender/%d/%s/update', [PHPWeb.MeasureURL, ARec.ValueByName('WebID').AsInteger, ANewName]);
  718. iRename := PHPWeb.Search(sURL, [], [], vArr);
  719. Result := iRename = 1;
  720. case iRename of
  721. 1: ShowMessage('新的标段名称已同步到服务器!');
  722. 0: Application.MessageBox(PChar(PHPWeb.PageError('重命名同步到云端失败' + '[' + vArr[0] + ']')),
  723. '警告', MB_OK + MB_ICONWARNING);
  724. -1: Application.MessageBox(PChar(PHPWeb.NetError('重命名同步到云端失败')),
  725. '警告', MB_OK + MB_ICONWARNING);
  726. end;
  727. end;
  728. var
  729. stnNode: TsdIDTreeNode;
  730. sName: string;
  731. begin
  732. stnNode := stdProjects.IDTree.Selected;
  733. sName := stnNode.Rec.ValueByName('Name').AsString;
  734. if not Assigned(OpenProjectManager.FindProjectData(stnNode.ID)) then
  735. begin
  736. if InputNewProjectName(sName, '重命名', stnNode.Parent, stnNode.ID) then
  737. begin
  738. if (sName <> stnNode.Rec.ValueByName('Name').AsString) and CanRename(stnNode.Rec, sName) then
  739. begin
  740. stnNode.Rec.ValueByName('Name').AsString := sName;
  741. ProjectManager.Save;
  742. end;
  743. end;
  744. end
  745. else
  746. ErrorMessage(Format('项目[%s]已经打开,无法重命名!', [sName]));
  747. end;
  748. procedure TProjectManagerFrame.actnOpenUpdate(Sender: TObject);
  749. begin
  750. TAction(Sender).Enabled := Assigned(stdProjects.IDTree.Selected)
  751. and (stdProjects.IDTree.Selected.Rec.ValueByName('Type').AsInteger = 1);
  752. end;
  753. procedure TProjectManagerFrame.actnImportExecute(Sender: TObject);
  754. procedure ImportTender(const AFileName, AProjectName: string);
  755. var
  756. Importor: TTenderImport;
  757. begin
  758. Importor := TTenderImport.Create(stdProjects.IDTree.Selected,
  759. AProjectName, AFileName);
  760. try
  761. Importor.Execute;
  762. finally
  763. Importor.Free;
  764. end;
  765. end;
  766. procedure ImportProject(const AFileName, AProjectName: string);
  767. var
  768. Importor: TProjectImport;
  769. begin
  770. Importor := TProjectImport.Create(stdProjects.IDTree.Selected,
  771. AProjectName, AFileName);
  772. try
  773. Importor.Execute;
  774. finally
  775. Importor.Free;
  776. end;
  777. end;
  778. var
  779. sFileName, sProjectName: string;
  780. vCur: TsdIDTreeNode;
  781. begin
  782. if SelectFile(sFileName, '.mtf;*.mpf') then
  783. begin
  784. vCur := stdProjects.IDTree.Selected;
  785. if Assigned(vCur) then
  786. begin
  787. if SameText(ExtractFileExt(sFileName), '.mtf')
  788. and (vCur.Rec.ValueByName('Type').AsInteger = 0) then
  789. sProjectName := GetImportProjectName(sFileName, stdProjects.IDTree.Selected)
  790. else
  791. sProjectName := GetImportProjectName(sFileName, stdProjects.IDTree.Selected.Parent);
  792. end
  793. else
  794. sProjectName := GetImportProjectName(sFileName, vCur);
  795. Screen.Cursor := crHourGlass;
  796. try
  797. if SameText(ExtractFileExt(sFileName), '.mtf') then
  798. ImportTender(sFileName, sProjectName)
  799. else
  800. ImportProject(sFileName, sProjectName);
  801. finally
  802. Screen.Cursor := crDefault;
  803. end;
  804. end;
  805. FProjectManagerData.Save;
  806. end;
  807. procedure TProjectManagerFrame.actnExportExecute(Sender: TObject);
  808. procedure ExportTender(ANode: TsdIDTreeNode);
  809. var
  810. Exportor: TTenderExport;
  811. sFileName, sHint: string;
  812. bExpAtch: Boolean;
  813. iCount: Integer;
  814. begin
  815. bExpAtch := False;
  816. sFileName := SupportManager.ConfigInfo.OutputPath + ANode.Rec.ValueByName('Name').AsString + '.mtf';
  817. if SaveFile(sFileName, '.mtf') then
  818. begin
  819. if FileExists(sFileName) and not QuestMessage(Format('存在同名文件“%s”,是否替换?', [ExtractFileName(sFileName)])) then
  820. Exit;
  821. Screen.Cursor := crHourGlass;
  822. try
  823. Exportor := TTenderExport.Create(ANode.Rec, sFileName);
  824. try
  825. { if not G_IsCloud then
  826. begin
  827. iCount := FileCount(CurRecAttachmentPath);
  828. if iCount > 1 then // 排除管理文件库
  829. begin
  830. sHint := Format('本标段包含 %d 个附件,是否将附件一起导出?', [iCount - 1]);
  831. bExpAtch := Application.MessageBox(PChar(sHint), '询问', MB_YESNO + MB_ICONQUESTION + MB_DEFBUTTON2) = ID_Yes;
  832. end;
  833. end; } // FFFFF
  834. Exportor.Execute(bExpAtch);
  835. finally
  836. Exportor.Free;
  837. end;
  838. finally
  839. Screen.Cursor := crDefault;
  840. end;
  841. end;
  842. end;
  843. procedure ExportProject(ANode: TsdIDTreeNode);
  844. var
  845. Exportor: TProjectExport;
  846. sFileName, sHint: string;
  847. bExpAtch: Boolean;
  848. iCount: Integer;
  849. begin
  850. sFileName := SupportManager.ConfigInfo.OutputPath + ANode.Rec.ValueByName('Name').AsString + '.mpf';
  851. if SaveFile(sFileName, '.mpf') then
  852. begin
  853. if FileExists(sFileName) and not QuestMessage(Format('存在同名文件“%s”,是否替换?', [ExtractFileName(sFileName)])) then
  854. Exit;
  855. Screen.Cursor := crHourGlass;
  856. try
  857. bExpAtch := False;
  858. { if not G_IsCloud then
  859. begin
  860. iCount := AttachmentFileCountsWithoutManageFile(ANode);
  861. if iCount > 0 then
  862. begin
  863. sHint := Format('本建设项目共包含 %d 个附件,是否将附件一起导出?', [iCount]);
  864. bExpAtch := Application.MessageBox(PChar(sHint), '询问', MB_YESNO + MB_ICONQUESTION + MB_DEFBUTTON2) = ID_Yes;
  865. end;
  866. end; } // FFFFF
  867. Exportor := TProjectExport.Create(ANode, sFileName, bExpAtch);
  868. try
  869. Exportor.Execute;
  870. finally
  871. Exportor.Free;
  872. end;
  873. finally
  874. Screen.Cursor := crDefault;
  875. end;
  876. end;
  877. end;
  878. var
  879. stnNode: TsdIDTreeNode;
  880. begin
  881. stnNode := stdProjects.IDTree.Selected;
  882. if stnNode.Rec.ValueByName('Type').AsInteger = 1 then
  883. begin
  884. ExportTender(stnNode);
  885. end
  886. else
  887. ExportProject(stnNode);
  888. end;
  889. procedure TProjectManagerFrame.actnDeleteUpdate(Sender: TObject);
  890. begin
  891. if Assigned(stdProjects.IDTree.Selected) then
  892. TAction(Sender).Enabled := not CheckOpened(stdProjects.IDTree.Selected)
  893. else
  894. TAction(Sender).Enabled := False;
  895. end;
  896. function TProjectManagerFrame.CheckOpened(ANode: TsdIDTreeNode): Boolean;
  897. var
  898. iChild: Integer;
  899. begin
  900. Result := False;
  901. if ANode.Rec.ValueByName('Type').AsInteger = 1 then
  902. Result := OpenProjectManager.ProjectIndex(ANode.ID) > -1
  903. else
  904. begin
  905. if not ANode.HasChildren then
  906. Result := False
  907. else
  908. begin
  909. for iChild := 0 to ANode.ChildCount - 1 do
  910. Result := Result or CheckOpened(ANode.ChildNodes[iChild]);
  911. end
  912. end;
  913. end;
  914. procedure TProjectManagerFrame.ShowProjectInfoTopAndCheckers;
  915. var
  916. vPSArr: TStrArr;
  917. vCArr: TOVArr; // Checkers
  918. vChecker: TOrderCheckerFrame;
  919. sPicPath, sURL: string;
  920. procedure AddChecker(AType: TCheckerFrameType; AArr: array of string);
  921. begin
  922. vChecker := TOrderCheckerFrame.Create(self);
  923. FCheckerList.Add(vChecker);
  924. vChecker.Owner := Self;
  925. sbChecker.VertScrollBar.Range := sbChecker.VertScrollBar.Range + vChecker.Height;
  926. sbChecker.Height := Min(sbChecker.Height + vChecker.Height, pnlWeb.Height - pnlProject.Height);
  927. vChecker.Parent := sbChecker;
  928. vChecker.Top := FCurPos;
  929. FCurPos := FCurPos + vChecker.Height;
  930. vChecker.Align := alTop;
  931. sPicPath := PHPWeb.UserPath + '1_' + AArr[0] + '.jpg';
  932. PHPWeb.DownFile(AArr[4], sPicPath);
  933. vChecker.Init(AType, StrToInt(AArr[0]), AArr[1], AArr[3],
  934. AArr[2], sPicPath, AArr[6], TCheckStatus(StrToInt(AArr[5])-1), AArr[8], StrToInt(AArr[7]));
  935. vChecker.Name := 'ProjectOrderFrame' + AArr[0];
  936. end;
  937. procedure RepairOrder;
  938. var k: Integer;
  939. begin
  940. for k := 0 to sbChecker.ControlCount - 1 do
  941. TOrderCheckerFrame(sbChecker.Controls[k]).Order := k + 1;
  942. end;
  943. procedure ShowProjectCheckers;
  944. var i, j, n: Integer;
  945. vOwner: array of string; // 业主信息
  946. begin
  947. FCheckerList.Clear;
  948. sbChecker.Height := 0;
  949. FCurPos := 0;
  950. n := Length(vCArr[Low(vCArr)]);
  951. SetLength(vOwner, n);
  952. sbChecker.VertScrollBar.Range := 0;
  953. for i := Low(vCArr) to High(vCArr) do
  954. begin
  955. if StrToInt(vCArr[i, 0]) = PHPWeb.UserID then
  956. FWebCheckStatusMy := TCheckStatus(StrToInt(vCArr[i, 5])-1);
  957. if StrToInt(vCArr[i, 0]) = FWebOwnerID then
  958. begin
  959. for j := 0 to n - 1 do
  960. vOwner[j] := vCArr[i, j];
  961. Continue;
  962. end;
  963. AddChecker(cftChecker, vCArr[i]);
  964. end;
  965. if vOwner[0] <> '' then
  966. AddChecker(cftOwner, vOwner);
  967. RepairOrder;
  968. OnLineChecker(vCArr, FOnLineCheckerBegin, FOnLineCheckerEnd, FOnLineCheckerEndIsOwner);
  969. end;
  970. begin
  971. GetLocalValues(CurRec);
  972. if FWebID = 0 then Exit;
  973. SetLength(vPSArr, 8);
  974. sURL := Format('%smeasure/status/%d/get', [PHPWeb.MeasureURL, FWebID]);
  975. if PHPWeb.Search(sURL, [''], [''], 3, vPSArr, vCArr) = 1 then
  976. begin
  977. LockWindowUpdate(pnlWeb.Handle);
  978. try
  979. FPhaseNo := StrToInt(vPSArr[0]);
  980. FWebCheckStatusProject := TCheckStatus(StrToInt(vPSArr[1])-1);
  981. FPhaseTotal := StrToInt(vPSArr[2]);
  982. FWebFolder_OnLine := vPSArr[3];
  983. FWebSubFolder_OnLine := vPSArr[4];
  984. FWebOwnerName := vPSArr[5];
  985. FWebOwnerCompany := vPSArr[6];
  986. FWebOwnerRole := vPSArr[7];
  987. ShowProjectInfoTop;
  988. ShowProjectCheckers;
  989. finally
  990. LockWindowUpdate(0);
  991. end;
  992. end
  993. else
  994. begin
  995. FPhaseNo := 0;
  996. FWebCheckStatusProject := csNotBegin;
  997. FPhaseTotal := 0;
  998. FWebFolder_OnLine := '';
  999. FWebSubFolder_OnLine := '';
  1000. FWebOwnerName := '';
  1001. FWebOwnerCompany := '';
  1002. FWebOwnerRole := '';
  1003. ShowProjectInfoTop;
  1004. sbChecker.Height := 0;
  1005. end;
  1006. end;
  1007. procedure TProjectManagerFrame.ShowProjectInfoTop(AType: Integer);
  1008. procedure ShowOwner;
  1009. begin
  1010. lblBidName.Caption := FWebBidName_Local;
  1011. lblBidName.Update;
  1012. lblProjName.Caption := FWebFolder_OnLine;
  1013. lblProjName.Update;
  1014. lblWebProjCtgyName.Caption := FWebSubFolder_OnLine;
  1015. lblWebProjCtgyName.Update;
  1016. lblOnwerName.Caption := FWebOwnerName;
  1017. lblOnwerName.Update;
  1018. lblOnwerCompany.Caption := Format('-%s)', [FWebOwnerCompany]);
  1019. lblOnwerCompany.Update;
  1020. lblOnwerCompany.Left := lblOnwerName.Left + lblOnwerName.Width;
  1021. end;
  1022. procedure ShowStatus(ANo: Integer; AState: TCheckStatus);
  1023. begin
  1024. lblPeriod.Caption := Format('第%d期', [ANo]);
  1025. lblPeriod.Update;
  1026. lblPeriodState.Caption := CheckStatusNames[AState];
  1027. lblPeriodState.Font.Color := CheckStatusColors[AState];
  1028. lblPeriodState.Update;
  1029. lblPeriodState.Left := lblPeriod.Left + lblPeriod.Width + 5;
  1030. lblPeriodTotal.Caption := Format('(共%d期)', [ANo]);
  1031. lblPeriodTotal.Update;
  1032. lblPeriodTotal.Left := lblPeriodState.Left + lblPeriodState.Width + 3;
  1033. end;
  1034. begin
  1035. GetLocalValues(CurRec);
  1036. case AType of
  1037. -2:
  1038. begin
  1039. lblPeriod.Caption := '正在从云端读取状态信息...';
  1040. lblPeriod.Update;
  1041. end;
  1042. -1:
  1043. begin
  1044. ShowOwner;
  1045. ShowStatus(FPhaseNo, FWebCheckStatusProject);
  1046. end;
  1047. 0:
  1048. begin
  1049. ShowOwner;
  1050. ShowStatus(0, csNotBegin);
  1051. end;
  1052. end;
  1053. end;
  1054. // 检查后,应该定位到最后一层目录,不应该回到原先的选择节点。否则从网络拉下来的项目无法组织正确的树结构。
  1055. procedure TProjectManagerFrame.CheckWebFolders(AFolderID, ASubFolderID: Integer;
  1056. AFolderName, ASubFolderName: string);
  1057. var
  1058. vTree: TsdIDTree;
  1059. vNode, vSubNode: TsdIDTreeNode;
  1060. i: Integer;
  1061. sName: string;
  1062. iUserID, iWebID, iWebFolderLevel: Integer;
  1063. bExist, bSubExist, bModified: Boolean;
  1064. begin
  1065. bExist := False;
  1066. bSubExist := False;
  1067. bModified := False;
  1068. vTree := stdProjects.IDTree;
  1069. for i := 0 to vTree.Count - 1 do
  1070. begin
  1071. vNode := vTree.Items[i];
  1072. sName := vNode.Rec.ValueByName('Name').AsString;
  1073. iUserID := vNode.Rec.ValueByName('WebUserID').AsInteger;
  1074. iWebID := vNode.Rec.ValueByName('WebID').AsInteger;
  1075. iWebFolderLevel := vNode.Rec.ValueByName('WebFolderLevel').AsInteger;
  1076. if (iWebID = AFolderID) and (iWebFolderLevel = G_WFL_ProjName) and (iUserID = PHPWeb.UserID) then
  1077. begin
  1078. bExist := True;
  1079. vNode.LocateInControl;
  1080. if not SameText(sName, AFolderName) then
  1081. begin
  1082. vNode.Rec.ValueByName('Name').AsString := AFolderName;
  1083. bModified := True;
  1084. end;
  1085. Break;
  1086. end;
  1087. end;
  1088. if not bExist then
  1089. begin
  1090. vNode := vTree.Items[0];
  1091. if Assigned(vNode) then
  1092. vNode.LocateInControl;
  1093. vNode := FProjectManagerData.InsertProject(AFolderName, stdProjects.IDTree.Selected, AFolderID, G_WFL_ProjName);
  1094. vNode.LocateInControl;
  1095. end;
  1096. for i := 0 to vNode.ChildCount - 1 do
  1097. begin
  1098. vSubNode := vNode.ChildNodes[i];
  1099. sName := vSubNode.Rec.ValueByName('Name').AsString;
  1100. iUserID := vSubNode.Rec.ValueByName('WebUserID').AsInteger;
  1101. iWebID := vSubNode.Rec.ValueByName('WebID').AsInteger;
  1102. iWebFolderLevel := vSubNode.Rec.ValueByName('WebFolderLevel').AsInteger;
  1103. if (iWebID = ASubFolderID) and (iWebFolderLevel = G_WFL_BidType) and (iUserID = PHPWeb.UserID) then
  1104. begin
  1105. bSubExist := True;
  1106. vSubNode.LocateInControl;
  1107. if not SameText(sName, ASubFolderName) then
  1108. begin
  1109. vSubNode.Rec.ValueByName('Name').AsString := ASubFolderName;
  1110. bModified := True;
  1111. end;
  1112. Break;
  1113. end;
  1114. end;
  1115. if not bSubExist then
  1116. begin
  1117. vNode.LocateInControl;
  1118. vNode := FProjectManagerData.InsertSubProject(ASubFolderName, stdProjects.IDTree.Selected, ASubFolderID, G_WFL_BidType);
  1119. vNode.LocateInControl;
  1120. end;
  1121. if bModified then
  1122. ProjectManager.Save;
  1123. end;
  1124. function TProjectManagerFrame.Rec(AProjectID: Integer): TsdDataRecord;
  1125. var i: Integer;
  1126. vTree: TsdIDTree;
  1127. begin
  1128. vTree := stdProjects.IDTree;
  1129. if vTree.Selected.Rec.ValueByName('ID').AsInteger = AProjectID then
  1130. begin
  1131. Result := stdProjects.IDTree.Selected.Rec;
  1132. Exit;
  1133. end;
  1134. for i := 0 to vTree.Count - 1 do
  1135. begin
  1136. if vTree.Items[i].Rec.ValueByName('ID').AsInteger = AProjectID then
  1137. begin
  1138. Result := vTree.Items[i].Rec;
  1139. vTree.Items[i].LocateInControl;
  1140. Break;
  1141. end;
  1142. end;
  1143. end;
  1144. destructor TProjectManagerFrame.Destroy;
  1145. begin
  1146. FCheckerList.Free;
  1147. inherited;
  1148. end;
  1149. procedure TProjectManagerFrame.DoBatchReceiveOnline(ARequestType: Integer);
  1150. var
  1151. sURL, sCheckersURL, sHint: string;
  1152. vArr: TOVArr;
  1153. i, iFolderID, iSubFolderID: Integer;
  1154. vPSArr: TStrArr;
  1155. vCArr: TOVArr; // Checkers
  1156. begin
  1157. // 查询等待我审核的标段文件,杰哥说分三种:①业主未审核 ②业主审核中 ③审核人审核中 (为什么加①?问杰哥)
  1158. case PHPWeb.Search(PHPWeb.MeasureURL + 'user/get/audit/project', ['audituid', 'RequestType'],
  1159. [IntToStr(PHPWeb.UserID), IntToStr(ARequestType)], vArr) of
  1160. 1:
  1161. begin
  1162. CreateProgress('正在从云端下载新项目');
  1163. try
  1164. for i := Low(vArr) to High(vArr) do
  1165. begin
  1166. sURL := vArr[i, 0];
  1167. FWebFolder_OnLine := vArr[i, 1];
  1168. FWebSubFolder_OnLine := vArr[i, 2];
  1169. FWebMD5_OnLine := vArr[i, 3];
  1170. FWebID := StrToInt(vArr[i, 5]);
  1171. iFolderID := StrToInt(vArr[i, 6]);
  1172. iSubFolderID := StrToInt(vArr[i, 7]);
  1173. FWebCheckStatusMy := TCheckStatus(StrToInt(vArr[i, 8])-1); // vArr[i, 4]项目审核状态;vArr[i, 8]当前登陆用户的审核状态
  1174. FWebAuthorID := StrToInt(vArr[i, 9]);
  1175. FWebBidName_OnLine := vArr[i, 10];
  1176. FWebMD5_Local := LocalMD5(PHPWeb.UserID, FWebID);
  1177. CheckWebFolders(iFolderID, iSubFolderID, FWebFolder_OnLine, FWebSubFolder_OnLine);
  1178. CheckBidName(PHPWeb.UserID, FWebID, FWebBidName_OnLine);
  1179. if FWebMD5_OnLine <> FWebMD5_Local then
  1180. begin
  1181. sCheckersURL := Format('%smeasure/status/%d/get', [PHPWeb.MeasureURL, FWebID]);
  1182. if PHPWeb.Search(sCheckersURL, [''], [''], 3, vPSArr, vCArr) = 1 then
  1183. OnLineChecker(vCArr, FOnLineCheckerBegin, FOnLineCheckerEnd, FOnLineCheckerEndIsOwner)
  1184. else
  1185. begin
  1186. FOnLineCheckerBegin := 0;
  1187. FOnLineCheckerEnd := 0;
  1188. end;
  1189. if not FileDownAndReceive(sURL, 1) then Exit;
  1190. end;
  1191. end;
  1192. BubbleSortProjects;
  1193. finally
  1194. CloseProgress;
  1195. end;
  1196. end;
  1197. 0, -1:
  1198. begin
  1199. sHint := '网络出错,无法查询云端项目的更新情况,请重试!';
  1200. Application.MessageBox(PChar(sHint), '警告', MB_OK + MB_ICONWARNING);
  1201. Exit;
  1202. end;
  1203. end;
  1204. end;
  1205. function TProjectManagerFrame.ImportFile(const AFileName: string; AFileMD5: string): Boolean;
  1206. var
  1207. vImport: TTenderImport;
  1208. vNode: TsdIDTreeNode;
  1209. begin
  1210. Result := False;
  1211. vNode := stdProjects.IDTree.Selected;
  1212. vImport := TTenderImport.Create(vNode, '', AFileName);
  1213. try
  1214. try
  1215. vImport.ImportToSelect;
  1216. vNode.LocateInControl;
  1217. Result := True;
  1218. except
  1219. Result := False;
  1220. end;
  1221. finally
  1222. vImport.Free;
  1223. vNode.Rec.BeginUpdate;
  1224. vNode.Rec.ValueByName('WebMD5').AsString := AFileMD5;
  1225. vNode.Rec.ValueByName('WebUserID').AsInteger := PHPWeb.UserID;
  1226. vNode.Rec.EndUpdate;
  1227. FProjectManagerData.Save;
  1228. end;
  1229. end;
  1230. procedure TProjectManagerFrame.actnOpenBackupFolderExecute(
  1231. Sender: TObject);
  1232. var
  1233. stnNode: TsdIDTreeNode;
  1234. begin
  1235. stnNode := stdProjects.IDTree.Selected;
  1236. if stnNode.Rec.ValueByName('BackupFolder').AsString = '' then
  1237. TipMessage('该项目暂无备份数据!')
  1238. else
  1239. ShellExecute(Handle, 'open', 'Explorer.exe',
  1240. PChar(FProjectManagerData.BackupPath(stnNode.ID)), nil, 1);
  1241. end;
  1242. procedure TProjectManagerFrame.actnRenameUpdate(Sender: TObject);
  1243. var
  1244. Rec: TsdDataRecord;
  1245. bNet, bEnabled: Boolean;
  1246. begin
  1247. if Assigned(stdProjects.IDTree.Selected) and Assigned(stdProjects.IDTree.Selected.Rec) then
  1248. begin
  1249. bEnabled := True;
  1250. Rec := stdProjects.IDTree.Selected.Rec;
  1251. bNet := G_IsCloud;
  1252. if bNet then
  1253. begin
  1254. bEnabled := (Rec.ValueByName('Type').AsInteger = 1) and
  1255. (Rec.ValueByName('WebAuthorID').AsInteger = PHPWeb.UserID);
  1256. end;
  1257. end
  1258. else
  1259. bEnabled := False;
  1260. if bEnabled <> TAction(Sender).Enabled then
  1261. TAction(Sender).Enabled := bEnabled;
  1262. end;
  1263. procedure TProjectManagerFrame.CheckBidName(AID: Integer; ANewBidName: string);
  1264. var vNode: TsdIDTreeNode;
  1265. begin
  1266. vNode := stdProjects.IDTree.FindNode(AID);
  1267. if vNode = nil then Exit;
  1268. if vNode.Rec.ValueByName('Name').AsString <> ANewBidName then
  1269. begin
  1270. vNode.Rec.ValueByName('Name').AsString := ANewBidName;
  1271. ProjectManager.Save;
  1272. end;
  1273. end;
  1274. procedure TProjectManagerFrame.DoBatchReceiveAllOnline;
  1275. var
  1276. OnCC: TZjCellNotifyEvent;
  1277. begin
  1278. OnCC := zgProjects.OnCurrentChanged;
  1279. try
  1280. zgProjects.OnCurrentChanged := nil;
  1281. DoBatchReceiveOnline(2);
  1282. if stdProjects.IDTree.FirstNode <> nil then
  1283. stdProjects.IDTree.FirstNode.LocateInControl;
  1284. finally
  1285. zgProjects.OnCurrentChanged := OnCC;
  1286. end;
  1287. end;
  1288. procedure TProjectManagerFrame.GetLocalValues(ARec: TsdDataRecord);
  1289. begin
  1290. if not Assigned(ARec) then
  1291. begin
  1292. ClearLocalValues;
  1293. Exit;
  1294. end;
  1295. // 加这句后产生Bug:上报项目后,记录不曾移动,FID不变,不会刷新
  1296. // if ARec.ValueByName('ID').AsInteger <> FID then
  1297. begin
  1298. FID := ARec.ValueByName('ID').AsInteger;
  1299. FWebID := ARec.ValueByName('WebID').AsInteger;
  1300. FWebAuthorID := ARec.ValueByName('WebAuthorID').AsInteger;
  1301. FWebOwnerID := ARec.ValueByName('WebOwnerID').AsInteger;
  1302. FWebMD5_Local := ARec.ValueByName('WebMD5').AsString;
  1303. FWebBidName_Local := ARec.ValueByName('Name').AsString;
  1304. end;
  1305. end;
  1306. procedure TProjectManagerFrame.GetLocalValues(AUserID, AWebID: Integer);
  1307. var i: Integer;
  1308. vTree: TsdIDTree;
  1309. vRec: TsdDataRecord;
  1310. begin
  1311. ClearLocalValues; // 先清空,以防没找到。
  1312. if (CurRec <> nil) and
  1313. (CurRec.ValueByName('WebUserID').AsInteger = AUserID) and
  1314. (CurRec.ValueByName('WebID').AsInteger = AWebID) and
  1315. (CurRec.ValueByName('Type').AsInteger = 1) then
  1316. begin
  1317. GetLocalValues(vRec);
  1318. Exit;
  1319. end;
  1320. vTree := stdProjects.IDTree;
  1321. for i := 0 to vTree.Count - 1 do
  1322. begin
  1323. vRec := vTree.Items[i].Rec;
  1324. if (vRec.ValueByName('WebUserID').AsInteger = AUserID) and
  1325. (vRec.ValueByName('WebID').AsInteger = AWebID) and
  1326. (vRec.ValueByName('Type').AsInteger = 1) then
  1327. begin
  1328. GetLocalValues(vRec);
  1329. Break;
  1330. end;
  1331. end;
  1332. end;
  1333. procedure TProjectManagerFrame.ClearLocalValues;
  1334. begin
  1335. FID := -1;
  1336. FWebID := -1;
  1337. FWebAuthorID := -1;
  1338. FWebOwnerID := -1;
  1339. FWebMD5_Local := '';
  1340. FWebBidName_Local := '';
  1341. end;
  1342. function TProjectManagerFrame.LocalMD5(AUserID, AWebID: Integer): string;
  1343. var i: Integer;
  1344. vTree: TsdIDTree;
  1345. vRec: TsdDataRecord;
  1346. begin
  1347. Result := '本地无MD5码';
  1348. if (CurRec <> nil) and
  1349. (CurRec.ValueByName('WebUserID').AsInteger = AUserID) and
  1350. (CurRec.ValueByName('WebID').AsInteger = AWebID) and
  1351. (CurRec.ValueByName('Type').AsInteger = 1) then
  1352. begin
  1353. Result := vRec.ValueByName('WebMD5').AsString;
  1354. Exit;
  1355. end;
  1356. vTree := stdProjects.IDTree;
  1357. for i := 0 to vTree.Count - 1 do
  1358. begin
  1359. vRec := vTree.Items[i].Rec;
  1360. if (vRec.ValueByName('WebUserID').AsInteger = AUserID) and
  1361. (vRec.ValueByName('WebID').AsInteger = AWebID) and
  1362. (vRec.ValueByName('Type').AsInteger = 1) then
  1363. begin
  1364. Result := vRec.ValueByName('WebMD5').AsString;
  1365. Break;
  1366. end;
  1367. end;
  1368. end;
  1369. function TProjectManagerFrame.CurRec: TsdDataRecord;
  1370. begin
  1371. if stdProjects.IDTree.Selected = nil then
  1372. Result := nil
  1373. else
  1374. Result := stdProjects.IDTree.Selected.Rec;
  1375. end;
  1376. procedure TProjectManagerFrame.CheckBidName(AUserID, AWebID: Integer;
  1377. ANewBidName: string);
  1378. var i: Integer;
  1379. vTree: TsdIDTree;
  1380. vRec: TsdDataRecord;
  1381. begin
  1382. if (CurRec <> nil) and
  1383. (CurRec.ValueByName('WebUserID').AsInteger = AUserID) and
  1384. (CurRec.ValueByName('WebID').AsInteger = AWebID) and
  1385. (CurRec.ValueByName('Type').AsInteger = 1) then
  1386. begin
  1387. if (CurRec.ValueByName('Name').AsString <> ANewBidName) then
  1388. begin
  1389. CurRec.ValueByName('Name').AsString := ANewBidName;
  1390. ProjectManager.Save;
  1391. end;
  1392. Exit;
  1393. end;
  1394. vTree := stdProjects.IDTree;
  1395. for i := 0 to vTree.Count - 1 do
  1396. begin
  1397. vRec := vTree.Items[i].Rec;
  1398. if (vRec.ValueByName('WebUserID').AsInteger = AUserID) and
  1399. (vRec.ValueByName('WebID').AsInteger = AWebID) and
  1400. (vRec.ValueByName('Type').AsInteger = 1) then
  1401. begin
  1402. if vRec.ValueByName('Name').AsString <> ANewBidName then
  1403. begin
  1404. vRec.ValueByName('Name').AsString := ANewBidName;
  1405. ProjectManager.Save;
  1406. end;
  1407. Break;
  1408. end;
  1409. end;
  1410. end;
  1411. function TProjectManagerFrame.CurRecAttachmentPath: string;
  1412. begin
  1413. if G_IsCloud then
  1414. Result := PHPWeb.WebPath + 'Projects\' + CurRec.ValueByName('WebID').AsString + '\Attachment\'
  1415. else
  1416. Result := GetMyProjectsFilePath + 'Attachment\' + CurRec.ValueByName('FileName').AsString + '\';
  1417. end;
  1418. function TProjectManagerFrame.AttachmentFileCountsWithoutManageFile(ANode: TsdIDTreeNode): Integer;
  1419. function GetCount(ANode: TsdIDTreeNode): Integer;
  1420. var sPath: string;
  1421. begin
  1422. if not Assigned(ANode) then Exit;
  1423. Result := 0;
  1424. if ANode.Rec.ValueByName('Type').AsInteger = 0 then
  1425. Result := Result + 0
  1426. else
  1427. begin
  1428. sPath := GetMyProjectsFilePath + 'Attachment\' + ANode.Rec.ValueByName('FileName').AsString + '\';
  1429. Result := Result + FileCount(sPath) - 1;
  1430. end;
  1431. if Assigned(ANode.FirstChild) then
  1432. Result := Result + GetCount(ANode.FirstChild);
  1433. if Assigned(ANode.NextSibling) then
  1434. Result := Result + GetCount(ANode.NextSibling);
  1435. end;
  1436. begin
  1437. if not Assigned(ANode) then Exit;
  1438. if Assigned(ANode.FirstChild) then
  1439. Result := GetCount(ANode.FirstChild)
  1440. else
  1441. Result := 0;
  1442. end;
  1443. procedure TProjectManagerFrame.BubbleSortProjects;
  1444. // 不能排最顶层
  1445. procedure BubbleSort(ANode: TsdIDTreeNode);
  1446. var n, t, c, temp: Integer;
  1447. bSwap: Boolean;
  1448. vNode1, vNode2, vTempNode: TsdIDTreeNode;
  1449. begin
  1450. if ANode = nil then Exit;
  1451. // if ANode.Rec.ValueByName('WebFolderLevel').AsInteger = G_WFL_ProjName then Exit;
  1452. n := ANode.ChildCount;
  1453. for t := 1 to n - 1 do
  1454. begin
  1455. bSwap := False;
  1456. for c := 1 to (n - t) do
  1457. begin
  1458. vNode1 := ANode.ChildNodes[c - 1];
  1459. vNode2 := ANode.ChildNodes[c];
  1460. if AnsiCompareStr(vNode1.Rec.ValueByName('Name').AsString,
  1461. vNode2.Rec.ValueByName('Name').AsString) = 1 then
  1462. begin
  1463. vNode1.DownMove;
  1464. bSwap := True;
  1465. end;
  1466. end;
  1467. if bSwap = False then Break;
  1468. end;
  1469. if Assigned(ANode.FirstChild) then
  1470. BubbleSort(ANode.FirstChild);
  1471. if Assigned(ANode.NextSibling) then
  1472. BubbleSort(ANode.NextSibling);
  1473. end;
  1474. begin
  1475. BubbleSort(stdProjects.IDTree.FirstNode);
  1476. end;
  1477. procedure TProjectManagerFrame.zgProjectsShowHint(var HintStr: String;
  1478. var CanShow: Boolean; var HintInfo: THintInfo; const ACoord: TPoint);
  1479. var
  1480. vCell: TZjCell;
  1481. vNode: TsdIDTreeNode;
  1482. iLevelWidth: Integer;
  1483. rText: TRect;
  1484. procedure CalcTextRect(var R: TRect);
  1485. var
  1486. DC: HDC;
  1487. iTextHeight: Integer;
  1488. begin
  1489. DC := CreateCompatibleDC(0);
  1490. try
  1491. SelectObject(DC, vCell.Font.Handle);
  1492. iTextHeight := DrawText(DC, PChar(vCell.Text), Length(vCell.Text), R, DT_SINGLELINE or DT_VCenter
  1493. or DT_NOCLIP or DT_CALCRECT);
  1494. finally
  1495. DeleteDC(DC);
  1496. end;
  1497. end;
  1498. begin
  1499. if (ACoord.Y < 1) and (ACoord.X <> 1) then Exit;
  1500. vCell := zgProjects.Cells[ACoord.X, ACoord.Y];
  1501. with HintInfo do
  1502. begin
  1503. vNode := stdProjects.IDTree.Items[ACoord.Y - 1];
  1504. if not Assigned(vNode) then Exit;
  1505. iLevelWidth := (vNode.Level + 1) * 20 + 16;
  1506. rText := CursorRect;
  1507. CalcTextRect(rText);
  1508. if (rText.Right - rText.Left + iLevelWidth > CursorRect.Right - CursorRect.Left) or
  1509. (rText.Right > ClientWidth) then
  1510. begin
  1511. CanShow := True;
  1512. HintStr := vCell.Text;
  1513. GetCursorPos(HintPos);
  1514. end;
  1515. end;
  1516. end;
  1517. function TProjectManagerFrame.FileDownAndReceive(ADownURL: string; AReceiveKind: Integer): Boolean;
  1518. var sLocalFile, sHint: string;
  1519. bCanImp: Boolean;
  1520. vFileCheck: TTenderFileChecker;
  1521. begin
  1522. Result := False;
  1523. // 下载
  1524. sLocalFile := PHPWeb.UserPath + ExtractFileName(ADownURL);
  1525. if not PHPWeb.DownFile(ADownURL, sLocalFile) then
  1526. begin
  1527. sHint := Format('云端已找到[%s]的新文件,但由于网络原因下载失败!请重试!', [FWebBidName_Local]);
  1528. Application.MessageBox(PChar(sHint), '系统提醒', MB_OK + MB_ICONWARNING);
  1529. Exit;
  1530. end;
  1531. // 接收前先检验原报文件是否正确(审核不通过打回)
  1532. if AReceiveKind = 2 then
  1533. begin
  1534. // 有时原报文件出错:包含了1审2审的数据。
  1535. vFileCheck := TTenderFileChecker.Create;
  1536. try
  1537. // 有一期以上数据,且最新期数据审核状态为原报
  1538. bCanImp := vFileCheck.CheckFileValid(sLocalFile) and (vFileCheck.PhaseCount > 0) and (vFileCheck.AuditStatus = 0);
  1539. if not bCanImp then
  1540. begin
  1541. Application.MessageBox(PChar('已从云端下载原报文件到本地,但文件有错误(包含1审数据)禁止接收!请致电纵横服务人员以获取帮助。'),
  1542. '警告', MB_OK + MB_ICONWARNING);
  1543. Exit;
  1544. end;
  1545. finally
  1546. vFileCheck.Free;
  1547. end;
  1548. {注意: 审核末通过的导入更新,这里的MD5码应取最终审核不通过项目的,否则会带来下载循环问题。
  1549. 问题描述:
  1550. ①编制人运行软件,双击项目,发现审核不通过,自动下载无锁文件,开始新一期,保存关闭。
  1551. ②编制人再次运行软件,双击项目,MD5码不同,自动下载旧的审核不通过文件,覆盖本地。
  1552. ③编制人再次运行软件,双击项目,发现审核不通过,重复①,循环....
  1553. 问:①那里下载无锁文件后不能改成新的MD5码吗?
  1554. 答:不能,因为审核人的项目会变成无锁文件,看不到不通过项目。MD5码只能在上传后更新。
  1555. 且编制人有个交互界面2种选择:a.下载更新不通过项目查看;b.下载更新无锁文件开始新一期。}
  1556. end;
  1557. // 接收更新
  1558. if not ReceiveFile(sLocalFile, (AReceiveKind = 2)) then
  1559. begin
  1560. sHint := Format('已从云端下载新的[%s]到本地[%s],但接收失败,请删除该项目然后重新从云端获取!', [FWebBidName_Local, sLocalFile]);
  1561. Application.MessageBox(PChar(sHint), '系统提醒', MB_OK + MB_ICONWARNING);
  1562. Exit;
  1563. end;
  1564. if FileExists(sLocalFile) then
  1565. DeleteFile(sLocalFile);
  1566. Result := True;
  1567. end;
  1568. // 为了跟PHP的数组兼容,这里限制数组的第一个元素是A[0](不能是A[1])
  1569. procedure TProjectManagerFrame.OnLineChecker(AAr: TOVArr; var ABegin,
  1570. AEnd: Integer; var AOnLineEndIsOwner: Boolean);
  1571. var i, j, n: Integer;
  1572. vCS: TCheckStatus;
  1573. begin
  1574. ABegin := 0;
  1575. AEnd := 0;
  1576. AOnLineEndIsOwner := AAr[High(AAr), 7] = '1';
  1577. n := -1;
  1578. for i := 0 to High(AAr) do
  1579. begin
  1580. vCS := TCheckStatus(StrToInt(AAr[i, 5])-1);
  1581. if vCS = csChecking then
  1582. begin
  1583. n := i - 1; // 非常重要:传入的数组必须从第一个审核人到轮到工作中的那个人的前一个人
  1584. Break;
  1585. end;
  1586. end;
  1587. for i := n downto 0 do
  1588. begin
  1589. if AAr[i, 7] = '1' then // 接口返回的第7列是线上审批标记
  1590. begin
  1591. AEnd := i + 1;
  1592. Break;
  1593. end
  1594. else
  1595. Break;
  1596. end;
  1597. if AEnd = 0 then Exit;
  1598. i := i - 1;
  1599. if i < 0 then
  1600. begin
  1601. ABegin := 1;
  1602. Exit;
  1603. end;
  1604. for j := i downto 0 do
  1605. begin
  1606. if AAr[j, 7] = '0' then
  1607. begin
  1608. ABegin := j + 2;
  1609. Break;
  1610. end
  1611. else
  1612. begin
  1613. if j = 0 then
  1614. ABegin := 1;
  1615. end;
  1616. end;
  1617. end;
  1618. procedure TProjectManagerFrame.actnExportUpdate(Sender: TObject);
  1619. begin
  1620. TAction(Sender).Enabled := Assigned(stdProjects.IDTree.Selected);
  1621. end;
  1622. procedure TProjectManagerFrame.actnOpenBackupFolderUpdate(Sender: TObject);
  1623. begin
  1624. TAction(Sender).Enabled := Assigned(stdProjects.IDTree.Selected) and
  1625. (stdProjects.IDTree.Selected.Rec.ValueByName('Type').AsInteger = 1);
  1626. end;
  1627. end.