ProjectManagerFme.pas 50 KB

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