ProjectManagerFme.pas 59 KB

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