ProjectManagerFme.pas 55 KB

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