ProjectManagerFme.pas 59 KB

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