ProjectManagerFme.pas 62 KB

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