ProjectManagerFme.pas 58 KB

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