ProjectManagerFme.pas 56 KB

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