ProjectManagerDm.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. unit ProjectManagerDm;
  2. interface
  3. uses
  4. TenderBackupManager,
  5. SysUtils, Classes, DB, DBClient, Provider, ADODB, Connections, ZhAPI,
  6. sdDB, sdProvider, sdIDTree;
  7. type
  8. TProjectManagerData = class(TDataModule)
  9. sdpProjectsInfo: TsdADOProvider;
  10. sddProjectsInfo: TsdDataSet;
  11. sdvProjectsInfo: TsdDataView;
  12. sdpTenderProperty: TsdADOProvider;
  13. sddTenderProperty: TsdDataSet;
  14. sdvTenderProperty: TsdDataView;
  15. procedure sdvProjectsInfoGetText(var Text: String;
  16. ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
  17. DisplayText: Boolean);
  18. procedure sdvProjectsInfoFilterRecord(ARecord: TsdDataRecord;
  19. var Allow: Boolean);
  20. procedure DataModuleCreate(Sender: TObject);
  21. procedure sdvProjectsInfoBeforeDeleteRecord(ARecord: TsdDataRecord;
  22. var Allow: Boolean);
  23. private
  24. FConnection: TEncryptConnection;
  25. FProjectsTree: TsdIDTree;
  26. FBackupManager: TBackupManager;
  27. procedure UpdateManagerDataBase;
  28. //procedure ReNameCurrentProject(const AName: string);
  29. procedure CreateNewProjectFile(const AName: string);
  30. procedure DeleteAllTenderFiles(ANode: TsdIDTreeNode);
  31. procedure DeleteAttachmentFiles(ANode: TsdIDTreeNode);
  32. function CreateBackupFolder(AProjectID: Integer): string;
  33. procedure ExportTender(ARec: TsdDataRecord; AFileName: string);
  34. function NewID: Integer;
  35. public
  36. constructor Create;
  37. destructor Destroy; override;
  38. procedure Open;
  39. procedure Save;
  40. function HasProject: Boolean;
  41. function ExistProject(const AName: string; ANode: TsdIDTreeNode): Boolean;
  42. function ProjectID(const AName: string; ANode: TsdIDTreeNode): Integer;
  43. // 云版要记下网络文件夹的ID和层次。
  44. function InsertProject(const AName: string; APreNode: TsdIDTreeNode; AFolderID: Integer = -1; AFolderLevel: Integer = -1): TsdIDTreeNode;
  45. function InsertSubProject(const AName: string; AParent: TsdIDTreeNode; AFolderID: Integer = -1; AFolderLevel: Integer = -1): TsdIDTreeNode;
  46. function InsertTender(const AName: string; AParent: TsdIDTreeNode): TsdIDTreeNode;
  47. procedure Delete;
  48. procedure ReName(const AName: string; ANode: TsdIDTreeNode);
  49. procedure RestoreTender(AID: Integer);
  50. procedure RefreshSeedID;
  51. function BackupPath(AProjectID: Integer): String;
  52. procedure AddOpenTenderBackup(AProjectID: Integer);
  53. procedure AddSaveTenderBackup(AProjectID: Integer);
  54. property ProjectsTree: TsdIDTree read FProjectsTree;
  55. end;
  56. implementation
  57. uses
  58. UtilMethods, UpdateDataBase, ProjectCommands, PHPWebDm, ConstUnit;
  59. {$R *.dfm}
  60. { TProjectManagerData }
  61. constructor TProjectManagerData.Create;
  62. begin
  63. inherited Create(nil);
  64. FConnection := TEncryptConnection.Create;
  65. FProjectsTree := TsdIDTree.Create;
  66. FProjectsTree.KeyFieldName := 'ID';
  67. FProjectsTree.ParentFieldName := 'ParentID';
  68. FProjectsTree.NextSiblingFieldName := 'NextSiblingID';
  69. FProjectsTree.AutoCreateKeyID := True;
  70. FProjectsTree.AutoExpand := True;
  71. FProjectsTree.SeedID := 1;
  72. FProjectsTree.DataView := sdvProjectsInfo;
  73. FBackupManager := TBackupManager.Create;
  74. end;
  75. procedure TProjectManagerData.CreateNewProjectFile(const AName: string);
  76. var
  77. TempFolder: string;
  78. begin
  79. try
  80. TempFolder := GenerateTempFolder(GetTempFilePath);
  81. CopyFileOrFolder(GetEmptyDataBaseFileName, TempFolder + '\Main.dat');
  82. ZipFolder(TempFolder, GetMyProjectsFilePath + AName);
  83. finally
  84. DeleteFileOrFolder(TempFolder);
  85. end;
  86. end;
  87. procedure TProjectManagerData.Delete;
  88. begin
  89. if HasProject then
  90. begin
  91. DeleteAttachmentFiles(FProjectsTree.Selected);
  92. DeleteAllTenderFiles(FProjectsTree.Selected);
  93. FProjectsTree.DeleteNode(FProjectsTree.Selected);
  94. Save;
  95. end;
  96. end;
  97. destructor TProjectManagerData.Destroy;
  98. begin
  99. FBackupManager.Free;
  100. FProjectsTree.Free;
  101. FConnection.Free;
  102. inherited;
  103. end;
  104. function TProjectManagerData.ExistProject(const AName: string;
  105. ANode: TsdIDTreeNode): Boolean;
  106. var
  107. vCur: TsdIDTreeNode;
  108. begin
  109. Result := False;
  110. if not Assigned(ANode) then Exit;
  111. vCur := ANode.FirstChild;
  112. while not Result and Assigned(vCur) do
  113. begin
  114. Result := vCur.Rec.ValueByName('Name').AsString = AName;
  115. vCur := vCur.NextSibling;
  116. end;
  117. end;
  118. function TProjectManagerData.HasProject: Boolean;
  119. begin
  120. Result := sddProjectsInfo.RecordCount > 0;
  121. end;
  122. function TProjectManagerData.InsertProject(const AName: string;
  123. APreNode: TsdIDTreeNode; AFolderID: Integer; AFolderLevel: Integer): TsdIDTreeNode;
  124. var
  125. vNew: TsdIDTreeNode;
  126. bOnLine, bCanCreate: Boolean;
  127. begin
  128. // 云版判断是否已存在的标准是服务端传来的ID,不是单机版所使用的名称。
  129. // 判断条件写在这里面不合适,因为云版调用不正确,应该写到方法外面。
  130. // 现在已经这样了,改起来麻烦,先补丁的方式用着。
  131. if G_IsCloud then
  132. bCanCreate := True
  133. else if (not G_IsCloud) and (not Assigned(APreNode)
  134. or not ExistProject(AName, APreNode.Parent)) then
  135. bCanCreate := True
  136. else
  137. bCanCreate := False;
  138. if bCanCreate then
  139. begin
  140. RefreshSeedID;
  141. if Assigned(APreNode) then
  142. vNew := FProjectsTree.Add(APreNode.ParentID, APreNode.NextSiblingID)
  143. else
  144. vNew := FProjectsTree.Add(-1, -1);
  145. vNew.Rec.BeginUpdate;
  146. vNew.Rec.ValueByName('Type').AsInteger := 0;
  147. vNew.Rec.ValueByName('Name').AsString := AName;
  148. {---------------------------------------------------------------------------
  149. 恼火的问题:直接写成下面这样,则第二句编译不进:
  150. if G_IsOnLine then
  151. vNew.Rec.ValueByName('WebUserID').AsInteger := PHPWeb.UserID;
  152. 这里用局部变量bOnLine转接一下,能解决问题。
  153. ---------------------------------------------------------------------------}
  154. bOnLine := G_IsCloud;
  155. if bOnLine then
  156. begin
  157. vNew.Rec.ValueByName('WebID').AsInteger := AFolderID;
  158. vNew.Rec.ValueByName('WebUserID').AsInteger := PHPWeb.UserID;
  159. vNew.Rec.ValueByName('WebFolderLevel').AsInteger := AFolderLevel;
  160. end;
  161. vNew.Rec.EndUpdate;
  162. Result := vNew;
  163. Save;
  164. end
  165. else
  166. raise Exception.Create('存在同名类别!');
  167. end;
  168. function TProjectManagerData.InsertSubProject(const AName: string;
  169. AParent: TsdIDTreeNode; AFolderID: Integer; AFolderLevel: Integer): TsdIDTreeNode;
  170. var
  171. vNew: TsdIDTreeNode;
  172. bOnLine, bCanCreate: Boolean;
  173. begin
  174. if G_IsCloud then
  175. bCanCreate := True
  176. else if (not G_IsCloud) and (not ExistProject(AName, AParent)) then
  177. bCanCreate := True
  178. else
  179. bCanCreate := False;
  180. if bCanCreate then
  181. begin
  182. RefreshSeedID;
  183. vNew := FProjectsTree.Add(AParent.ID, -1);
  184. vNew.Rec.ValueByName('Type').AsInteger := 0;
  185. vNew.Rec.ValueByName('Name').AsString := AName;
  186. {---------------------------------------------------------------------------
  187. 恼火的问题:直接写成下面这样,则第二句编译不进:
  188. if G_IsOnLine then
  189. vNew.Rec.ValueByName('WebUserID').AsInteger := PHPWeb.UserID;
  190. 这里用局部变量bOnLine转接一下,能解决问题。
  191. ---------------------------------------------------------------------------}
  192. bOnLine := G_IsCloud;
  193. if bOnLine then
  194. begin
  195. vNew.Rec.ValueByName('WebID').AsInteger := AFolderID;
  196. vNew.Rec.ValueByName('WebUserID').AsInteger := PHPWeb.UserID;
  197. vNew.Rec.ValueByName('WebFolderLevel').AsInteger := AFolderLevel;
  198. end;
  199. Result := vNew;
  200. Save;
  201. end
  202. else
  203. raise Exception.Create('存在同名类别!');
  204. end;
  205. function TProjectManagerData.InsertTender(const AName: string;
  206. AParent: TsdIDTreeNode): TsdIDTreeNode;
  207. var bOnLine: Boolean;
  208. begin
  209. if not ExistProject(AName, AParent) then
  210. begin
  211. RefreshSeedID;
  212. Result := FProjectsTree.Add(AParent.ID, -1);
  213. {---------------------------------------------------------------------------
  214. 恼火的问题:直接写成下面这样,则第二句编译不进:
  215. if G_IsOnLine then
  216. Result.Rec.ValueByName('WebUserID').AsInteger := PHPWeb.UserID;
  217. 这里用局部变量bOnLine转接一下,能解决问题。
  218. ---------------------------------------------------------------------------}
  219. // if G_IsOnLine then
  220. // Result.Rec.ValueByName('WebUserID').AsInteger := PHPWeb.UserID; // 编译不进
  221. bOnLine := G_IsCloud;
  222. if bOnLine then
  223. Result.Rec.ValueByName('WebUserID').AsInteger := PHPWeb.UserID;
  224. Result.Rec.ValueByName('Type').AsInteger := 1;
  225. Result.Rec.ValueByName('Name').AsString := AName;
  226. Result.Rec.ValueByName('PhaseCount').AsInteger := 0;
  227. Result.Rec.ValueByName('AuditStatus').AsInteger := 0;
  228. Result.Rec.ValueByName('FileName').AsString :=
  229. ExtractSimpleFileName(GetNewGUIDFileName(GetMyProjectsFilePath));
  230. Result.Rec.ValueByName('CreateDate').AsString := FormatDateTime('yyyy-mm-dd', Date);
  231. CreateNewProjectFile(Result.Rec.ValueByName('FileName').AsString);
  232. Save;
  233. end
  234. else
  235. raise Exception.Create('存在同名标段!');
  236. end;
  237. procedure TProjectManagerData.Open;
  238. var
  239. FQuery: TADOQuery;
  240. begin
  241. FConnection.Open(GetAppFilePath + 'Data\ProjectManager.dat');
  242. UpdateManagerDataBase;
  243. sdpProjectsInfo.Connection := FConnection.Connection;
  244. sddProjectsInfo.Open;
  245. sdvProjectsInfo.Open;
  246. sddProjectsInfo.AddIndex('idxID', 'ID');
  247. sdvProjectsInfo.IndexName := 'idxID';
  248. sdpTenderProperty.Connection := FConnection.Connection;
  249. sddTenderProperty.Open;
  250. sdvTenderProperty.Open;
  251. end;
  252. procedure TProjectManagerData.Save;
  253. begin
  254. sddTenderProperty.Save;
  255. sddProjectsInfo.Save;
  256. FConnection.Save;
  257. end;
  258. procedure TProjectManagerData.UpdateManagerDataBase;
  259. var
  260. vUpdator: TUpdateManagerDB;
  261. begin
  262. vUpdator := TUpdateManagerDB.Create;
  263. try
  264. vUpdator.Update(FConnection);
  265. finally
  266. vUpdator.Free;
  267. end;
  268. end;
  269. procedure TProjectManagerData.sdvProjectsInfoGetText(var Text: String;
  270. ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
  271. DisplayText: Boolean);
  272. function NumToAuditStatus(AValue: Integer): string;
  273. begin
  274. case AValue of
  275. -1:
  276. if ARecord.ValueByName('PhaseCount').AsInteger = 0 then
  277. Result := '原报'
  278. else
  279. Result := '批复';
  280. 0:
  281. Result := '原报';
  282. else
  283. Result := Format('%d 审', [AValue]);
  284. end;
  285. end;
  286. begin
  287. if not Assigned(ARecord) then Exit;
  288. if SameText(AColumn.FieldName, 'AuditStatus') then
  289. if ARecord.ValueByName('Type').AsInteger = 1 then
  290. Text := NumToAuditStatus(AValue.AsInteger)
  291. else
  292. Text := '';
  293. end;
  294. procedure TProjectManagerData.DeleteAllTenderFiles(ANode: TsdIDTreeNode);
  295. var
  296. iChild: Integer;
  297. begin
  298. if ANode.HasChildren then
  299. for iChild := 0 to ANode.ChildCount - 1 do
  300. DeleteAllTenderFiles(ANode.ChildNodes[iChild])
  301. else if ANode.Rec.ValueByName('Type').AsInteger = 1 then
  302. DeleteFile(GetMyProjectsFilePath + ANode.Rec.ValueByName('FileName').AsString);
  303. end;
  304. procedure TProjectManagerData.ReName(const AName: string;
  305. ANode: TsdIDTreeNode);
  306. begin
  307. ANode.Rec.ValueByName('Name').AsString := AName;
  308. Save;
  309. end;
  310. procedure TProjectManagerData.RestoreTender(AID: Integer);
  311. var
  312. vNode: TsdIDTreeNode;
  313. sRestoreFile: string;
  314. Exportor: TTenderExport;
  315. begin
  316. vNode := FProjectsTree.FindNode(AID);
  317. if not FileExists(GetMyProjectsFilePath + vNode.Rec.ValueByName('FileName').AsString) then Exit;
  318. sRestoreFile := GetBackUpFilePath + vNode.Rec.ValueByName('Name').AsString
  319. + '[' + FormatDateTime('yyyy-mm-dd hh,nn,ss', Now) + '].mtf';
  320. Exportor := TTenderExport.Create(vNode.Rec, sRestoreFile);
  321. try
  322. Exportor.Execute;
  323. finally
  324. Exportor.Free;
  325. end;
  326. end;
  327. procedure TProjectManagerData.sdvProjectsInfoFilterRecord(
  328. ARecord: TsdDataRecord; var Allow: Boolean);
  329. begin
  330. if G_IsCloud then
  331. begin
  332. if ARecord.ValueByName('WebUserID').AsInteger = PHPWeb.UserID then
  333. Allow := True
  334. else
  335. Allow := False;
  336. end
  337. else
  338. begin
  339. if ARecord.ValueByName('WebUserID').AsInteger = 0 then
  340. Allow := True
  341. else
  342. Allow := False;
  343. end;
  344. end;
  345. procedure TProjectManagerData.DataModuleCreate(Sender: TObject);
  346. begin
  347. // 单机版也要过滤:防止单机版程序能显示所有用户的项目。
  348. // if G_IsOnLine then
  349. sdvProjectsInfo.Filtered := True;
  350. end;
  351. function TProjectManagerData.NewID: Integer;
  352. var
  353. idxID: TsdIndex;
  354. begin
  355. idxID := sddProjectsInfo.FindIndex('idxID');
  356. Result := idxID.Records[idxID.RecordCount - 1].ValueByName('ID').AsInteger + 1;
  357. end;
  358. procedure TProjectManagerData.RefreshSeedID;
  359. begin
  360. FProjectsTree.SeedID := NewID;
  361. end;
  362. function TProjectManagerData.BackupPath(AProjectID: Integer): String;
  363. var
  364. Rec: TsdDataRecord;
  365. begin
  366. Result := GetAppFilePath + 'FileBackup\TenderBackup';
  367. Rec := ProjectsTree.FindNode(AProjectID).Rec;
  368. if Rec.ValueByName('BackupFolder').AsString = '' then
  369. Rec.ValueByName('BackupFolder').AsString := CreateBackupFolder(AProjectID);
  370. Result := Result + '\' + Rec.ValueByName('BackupFolder').AsString + '\';
  371. end;
  372. function TProjectManagerData.CreateBackupFolder(
  373. AProjectID: Integer): string;
  374. function GetParentNames(ANode: TsdIDTreeNode): string;
  375. var
  376. stnParent: TsdIDTreeNode;
  377. begin
  378. Result := '';
  379. stnParent := ANode.Parent;
  380. while Assigned(stnParent) do
  381. begin
  382. if Result <> '' then
  383. Result := stnParent.Rec.ValueByName('Name').AsString + '--' + Result
  384. else
  385. Result := stnParent.Rec.ValueByName('Name').AsString;
  386. stnParent := stnParent.Parent;
  387. end;
  388. end;
  389. var
  390. stnNode: TsdIDTreeNode;
  391. sGUID, sPath: string;
  392. sgs: TStringList;
  393. begin
  394. stnNode := ProjectsTree.FindNode(AProjectID);
  395. Result := stnNode.Rec.ValueByName('BackupFolder').AsString;
  396. if Result <> '' then Exit;
  397. sPath := GetAppFilePath + 'FileBackup\TenderBackup\';
  398. sGUID := GetNewGUIDFileName(sPath);
  399. if FileExists(sGUID) then DeleteFile(sGUID);
  400. CreateDirectoryInDeep(sGUID);
  401. sgs := TStringList.Create;
  402. try
  403. sgs.Add('项目备份文件夹');
  404. sgs.Add(Format('项目名称:%s', [stnNode.Rec.ValueByName('Name').AsString]));
  405. sgs.Add(Format('所属项目:%s', [GetParentNames(stnNode)]));
  406. sgs.Add(Format('创建时间:%s', [DateTimeToStr(Now)]));
  407. finally
  408. sgs.SaveToFile(sGUID + '\说明.txt');
  409. sgs.Free;
  410. end;
  411. Result := ExtractSimpleFileName(sGUID)
  412. end;
  413. procedure TProjectManagerData.sdvProjectsInfoBeforeDeleteRecord(
  414. ARecord: TsdDataRecord; var Allow: Boolean);
  415. var
  416. sOrgFolder, sNewFolder: string;
  417. begin
  418. if ARecord.ValueByName('BackupFolder').AsString <> '' then
  419. begin
  420. sOrgFolder := GetAppFilePath + 'FileBackup\TenderBackup\'
  421. + ARecord.ValueByName('BackupFolder').AsString;
  422. sNewFolder := GetAppFilePath + 'FileBackup\RecycleBackup\'
  423. + ARecord.ValueByName('BackupFolder').AsString;
  424. CopyFileOrFolder(sOrgFolder, sNewFolder);
  425. DeleteFileOrFolder(sOrgFolder);
  426. end;
  427. end;
  428. procedure TProjectManagerData.AddOpenTenderBackup(AProjectID: Integer);
  429. var
  430. BackupRec, Rec: TsdDataRecord;
  431. sBackupFile: string;
  432. begin
  433. Rec := sddProjectsInfo.FindKey('idxID', AProjectID);
  434. if not Assigned(Rec) then Exit;
  435. FBackupManager.LoadBackupFile(BackupPath(AProjectID));
  436. if FBackupManager.LastestOpenBackupIsToday then Exit;
  437. sBackupFile := FBackupManager.OpenBackupFile;
  438. if FileExists(sBackupFile) then DeleteFile(sBackupFile);
  439. ExportTender(Rec, sBackupFile);
  440. end;
  441. procedure TProjectManagerData.AddSaveTenderBackup(AProjectID: Integer);
  442. var
  443. BackupRec, Rec: TsdDataRecord;
  444. sBackupFile: string;
  445. begin
  446. Rec := sddProjectsInfo.FindKey('idxID', AProjectID);
  447. if not Assigned(Rec) then Exit;
  448. FBackupManager.LoadBackupFile(BackupPath(AProjectID));
  449. sBackupFile := FBackupManager.SaveBackupFile;
  450. if FileExists(sBackupFile) then DeleteFile(sBackupFile);
  451. ExportTender(Rec, sBackupFile);
  452. end;
  453. procedure TProjectManagerData.ExportTender(ARec: TsdDataRecord;
  454. AFileName: string);
  455. var
  456. Exportor : TTenderExport;
  457. begin
  458. Exportor := TTenderExport.Create(ARec, AFileName);
  459. try
  460. Exportor.Execute;
  461. finally
  462. Exportor.Free;
  463. end;
  464. end;
  465. function TProjectManagerData.ProjectID(const AName: string;
  466. ANode: TsdIDTreeNode): Integer;
  467. var
  468. vCur: TsdIDTreeNode;
  469. begin
  470. Result := -1;
  471. if not Assigned(ANode) then Exit;
  472. vCur := ANode.FirstChild;
  473. while (Result = -1) and Assigned(vCur) do
  474. begin
  475. if vCur.Rec.ValueByName('Name').AsString = AName then
  476. Result := vCur.ID;
  477. vCur := vCur.NextSibling;
  478. end;
  479. end;
  480. procedure TProjectManagerData.DeleteAttachmentFiles(ANode: TsdIDTreeNode);
  481. var sDir: string;
  482. procedure DeleteAtch(ANode: TsdIDTreeNode);
  483. begin
  484. // 如果文件名为空,删除时会删除整个附件文件夹,危险!
  485. if ANode.Rec.ValueByName('FileName').AsString = '' then Exit;
  486. sDir := GetMyProjectsFilePath + 'Attachment\' + ANode.Rec.ValueByName('FileName').AsString;
  487. DeleteFolder(sDir);
  488. end;
  489. procedure DeleteNodes(ANode: TsdIDTreeNode);
  490. begin
  491. if ANode = nil then Exit;
  492. if ANode.FirstChild <> nil then
  493. DeleteNodes(ANode.FirstChild);
  494. if ANode.Rec.ValueByName('Type').AsInteger = 1 then
  495. DeleteAtch(ANode);
  496. if ANode.NextSibling <> nil then
  497. DeleteNodes(ANode.NextSibling);
  498. end;
  499. begin
  500. if not G_IsCloud then
  501. begin
  502. if not Assigned(ANode) then Exit;
  503. if ANode.Rec.ValueByName('Type').AsInteger = 0 then
  504. begin
  505. if Assigned(ANode.FirstChild) then
  506. DeleteNodes(ANode.FirstChild);
  507. end
  508. else
  509. DeleteAtch(ANode);
  510. end;
  511. end;
  512. end.