ProjectManagerFme.pas 64 KB

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