ProjectManagerFme.pas 65 KB

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