ProjectManagerFme.pas 61 KB

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