ProjectManagerFme.pas 58 KB

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