@brggroup/share-lib 0.1.73 → 0.1.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -670,6 +670,7 @@ const URLs$j = {
670
670
  changePassword: '/api/Auth/ChangePassword',
671
671
  setPass: '/api/Auth/SetPass',
672
672
  changeOrgLogin: '/api/Auth/changeOrgLogin',
673
+ getUserPermission: '/api/Auth/getUserPermission',
673
674
  };
674
675
  class AuthService extends HTTPService {
675
676
  notiService = inject(NotiService);
@@ -762,6 +763,15 @@ class AuthService extends HTTPService {
762
763
  return false;
763
764
  }
764
765
  }
766
+ async getUserPermission() {
767
+ try {
768
+ const res = await this.get(AppGlobals.apiEndpoint + URLs$j.getUserPermission, true);
769
+ return res.Data;
770
+ }
771
+ catch {
772
+ return null;
773
+ }
774
+ }
765
775
  /* ----------------------------------------
766
776
  MENU
767
777
  ---------------------------------------- */
@@ -907,8 +917,7 @@ function checkRole(user, expectedRole) {
907
917
  }
908
918
 
909
919
  let PermissionService$1 = class PermissionService {
910
- static debug = false;
911
- cms = inject(CommonService);
920
+ authService = inject(AuthService);
912
921
  currentUser$ = new BehaviorSubject(null);
913
922
  // Hứng luật từ App. Nếu App không truyền thì lấy object rỗng {}
914
923
  appRules = inject(ABAC_RULES_TOKEN, { optional: true }) || {};
@@ -916,41 +925,16 @@ let PermissionService$1 = class PermissionService {
916
925
  this.currentUser$.next(user);
917
926
  }
918
927
  async getUserPermission() {
919
- // 1. Caching: Đã có data rồi thì thôi không gọi nữa
920
- if (this.currentUser$.value)
921
- return true;
922
928
  try {
923
- let data = {
924
- SPN: 'Permission_getUserPermission',
925
- };
926
- let ret = await this.cms.ESP(data);
927
- if (ret && ret.IsSuccess && ret.Data) {
928
- // 2. Xử lý an toàn các mảng chuỗi (Split, Trim, Filter)
929
- const parseStringToArray = (str) => {
930
- if (!str)
931
- return [];
932
- return str
933
- .split(',')
934
- .map((item) => item.trim()) // Xóa khoảng trắng thừa
935
- .filter((item) => item.length > 0); // Bỏ các phần tử rỗng
936
- };
937
- let user = {
938
- id: ret.Data.userid || '',
939
- username: ret.Data.username || '',
940
- roles: parseStringToArray(ret.Data.roles),
941
- permissions: parseStringToArray(ret.Data.permissions),
942
- };
943
- this.setCurrentUser(user);
944
- return true;
945
- }
946
- else {
947
- console.warn('Không lấy được thông tin quyền của User');
929
+ let user = await this.authService.getUserPermission();
930
+ if (!user)
948
931
  return false;
949
- }
932
+ this.setCurrentUser(user);
933
+ return true;
950
934
  }
951
935
  catch (error) {
952
936
  console.error('Lỗi API khi lấy quyền User:', error);
953
- return false; // Trả về false để Guard biết luồng bị lỗi
937
+ return false;
954
938
  }
955
939
  }
956
940
  hasAccess(resource, action, data) {
@@ -7943,12 +7927,6 @@ class FileService extends HTTPService {
7943
7927
  moveFileToDisk(obj) {
7944
7928
  return this.postData(AppGlobals.apiEndpoint + URLs$c.moveFileToDisk, obj);
7945
7929
  }
7946
- getPaging_HDSD(filter) {
7947
- return this.cms.ESP({
7948
- SPN: 'App_File_getpaging_HDSD',
7949
- Params: [filter],
7950
- });
7951
- }
7952
7930
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: FileService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
7953
7931
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: FileService, providedIn: 'root' });
7954
7932
  }
@@ -9285,10 +9263,7 @@ class SequenceService extends HTTPService {
9285
9263
  return this.postData(AppGlobals.apiEndpoint + URLs$9.getList, filter);
9286
9264
  }
9287
9265
  getPaging(filter) {
9288
- return this.commonService.ESP({
9289
- SPN: 'App_Sequence_getPaging',
9290
- Params: [filter],
9291
- });
9266
+ return this.postData(AppGlobals.apiEndpoint + URLs$9.getPaging, filter);
9292
9267
  }
9293
9268
  addOrEdit(obj) {
9294
9269
  return this.commonService.ESP({
@@ -14619,11 +14594,9 @@ class LayoutUser extends BaseComponent {
14619
14594
  if (this.hdsdData)
14620
14595
  return; // Nếu đã load rồi thì không load lại
14621
14596
  const filter = new FileFilter();
14622
- filter.PageIndex = 0;
14623
- filter.PageSize = 100;
14624
14597
  filter.Code = 'HDSD';
14625
14598
  this.loadingHDSD = true;
14626
- this.fileService.getPaging_HDSD(filter).then((res) => {
14599
+ this.fileService.getPaging(filter).then((res) => {
14627
14600
  this.hdsdData = res.Data;
14628
14601
  this.loadingHDSD = false;
14629
14602
  }, (err) => {
@@ -18469,6 +18442,10 @@ class WorkflowTemplateEdge {
18469
18442
  Id;
18470
18443
  From_WF_Template_Id;
18471
18444
  To_WF_Template_Id;
18445
+ From_WF_TemplateStage_Id;
18446
+ To_WF_TemplateStage_Id;
18447
+ From_WF_TemplateStageAction_Id;
18448
+ To_WF_TemplateStageAction_Id;
18472
18449
  FromStage;
18473
18450
  ToStage;
18474
18451
  FromAction;
@@ -18479,6 +18456,10 @@ class WorkflowTemplateEdge {
18479
18456
  this.Id = obj.Id || Date.now().toString();
18480
18457
  this.From_WF_Template_Id = obj.From_WF_Template_Id || null;
18481
18458
  this.To_WF_Template_Id = obj.To_WF_Template_Id || null;
18459
+ this.From_WF_TemplateStage_Id = obj.From_WF_TemplateStage_Id || null;
18460
+ this.To_WF_TemplateStage_Id = obj.To_WF_TemplateStage_Id || null;
18461
+ this.From_WF_TemplateStageAction_Id = obj.From_WF_TemplateStageAction_Id || null;
18462
+ this.To_WF_TemplateStageAction_Id = obj.To_WF_TemplateStageAction_Id || null;
18482
18463
  this.FromStage = obj.FromStage || '';
18483
18464
  this.ToStage = obj.ToStage || '';
18484
18465
  this.FromAction = obj.FromAction || '';
@@ -18524,6 +18505,7 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
18524
18505
  draggingGroup = false;
18525
18506
  dragStartMouse;
18526
18507
  dragStartPositions = new Map();
18508
+ dragStartEdgePoints = new Map();
18527
18509
  draggingNode;
18528
18510
  isDragging = false;
18529
18511
  dragStartX = 0;
@@ -18776,6 +18758,7 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
18776
18758
  const snap = this.snapPoint({ x: this.dragStartMouse.x + dx, y: this.dragStartMouse.y + dy }, event);
18777
18759
  const sdx = snap.x - this.dragStartMouse.x;
18778
18760
  const sdy = snap.y - this.dragStartMouse.y;
18761
+ // 1. Cập nhật vị trí mới cho các Nodes
18779
18762
  for (const n of this.lstTemplateNode) {
18780
18763
  if (!this.lstSelectedTemplateId.has(n.WF_Template_Id))
18781
18764
  continue;
@@ -18783,6 +18766,15 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
18783
18766
  n.editorOption.x = start.x + sdx;
18784
18767
  n.editorOption.y = start.y + sdy;
18785
18768
  }
18769
+ // 2. Cập nhật vị trí mới cho các Waypoint đi kèm
18770
+ this.dragStartEdgePoints.forEach((startPoints, edge) => {
18771
+ if (edge.editorOption.points) {
18772
+ for (let i = 0; i < startPoints.length; i++) {
18773
+ edge.editorOption.points[i].x = startPoints[i].x + sdx;
18774
+ edge.editorOption.points[i].y = startPoints[i].y + sdy;
18775
+ }
18776
+ }
18777
+ });
18786
18778
  return;
18787
18779
  }
18788
18780
  if (this.draggingNode) {
@@ -18847,18 +18839,33 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
18847
18839
  return;
18848
18840
  this.axisLock = null;
18849
18841
  const p = this.getSvgPoint(event);
18842
+ // KÉO THẢ NHIỀU NODE (GROUP)
18850
18843
  if (this.lstSelectedTemplateId.has(node.WF_Template_Id)) {
18851
18844
  this.pushUndo({ type: 'move-nodes', before: this.cloneNodePositions(this.lstSelectedTemplateId) });
18852
18845
  this.draggingGroup = true;
18853
18846
  this.dragStartMouse = p;
18854
18847
  this.dragStartPositions.clear();
18848
+ this.dragStartEdgePoints.clear(); // Xóa dữ liệu cũ
18849
+ // 1. Lưu vị trí ban đầu của các Node được chọn
18855
18850
  for (const n of this.lstTemplateNode) {
18856
18851
  if (this.lstSelectedTemplateId.has(n.WF_Template_Id)) {
18857
18852
  this.dragStartPositions.set(n.WF_Template_Id, { x: n.editorOption.x, y: n.editorOption.y });
18858
18853
  }
18859
18854
  }
18855
+ // 2. Lưu vị trí ban đầu của các Waypoint (điểm bẻ cong) thuộc các đường nối nội bộ
18856
+ for (const edge of this.lstTemplateEdge) {
18857
+ if (this.lstSelectedTemplateId.has(edge.From_WF_Template_Id) &&
18858
+ this.lstSelectedTemplateId.has(edge.To_WF_Template_Id) &&
18859
+ edge.editorOption.points &&
18860
+ edge.editorOption.points.length > 0) {
18861
+ // Clone mảng tọa độ waypoint ra để lưu
18862
+ const clonedPoints = edge.editorOption.points.map((pt) => ({ x: pt.x, y: pt.y }));
18863
+ this.dragStartEdgePoints.set(edge, clonedPoints);
18864
+ }
18865
+ }
18860
18866
  return;
18861
18867
  }
18868
+ // KÉO THẢ 1 NODE
18862
18869
  this.lstSelectedTemplateId.clear();
18863
18870
  this.hoverTemplateNode = undefined;
18864
18871
  this.pushUndo({ type: 'move-nodes', before: this.cloneNodePositions(new Set([node.WF_Template_Id])) });
@@ -19229,12 +19236,24 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
19229
19236
  if (this.lstSelectedTemplateId.size === 0)
19230
19237
  return;
19231
19238
  this.pushUndo({ type: 'move-nodes', before: this.cloneNodePositions(this.lstSelectedTemplateId) });
19239
+ // 1. Di chuyển các Node
19232
19240
  for (const n of this.lstTemplateNode) {
19233
19241
  if (!this.lstSelectedTemplateId.has(n.WF_Template_Id))
19234
19242
  continue;
19235
19243
  n.editorOption.x = this.clamp(n.editorOption.x + dx, 0, this.getCanvasWidth() - this.NODE_WIDTH);
19236
19244
  n.editorOption.y = this.clamp(n.editorOption.y + dy, 0, this.getCanvasHeight() - this.NODE_HEIGHT);
19237
19245
  }
19246
+ // 2. Di chuyển các Waypoint của đường nối nội bộ
19247
+ for (const edge of this.lstTemplateEdge) {
19248
+ if (this.lstSelectedTemplateId.has(edge.From_WF_Template_Id) &&
19249
+ this.lstSelectedTemplateId.has(edge.To_WF_Template_Id) &&
19250
+ edge.editorOption.points) {
19251
+ for (const pt of edge.editorOption.points) {
19252
+ pt.x += dx;
19253
+ pt.y += dy;
19254
+ }
19255
+ }
19256
+ }
19238
19257
  }
19239
19258
  // ALIGNMENT
19240
19259
  getSelectedNodes() {
@@ -19438,7 +19457,7 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
19438
19457
  }
19439
19458
  }
19440
19459
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WF_Template_CombineEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
19441
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: WF_Template_CombineEditorComponent, isStandalone: true, selector: "app-workflow-combine-editor", inputs: { lstTemplateForSelect: "lstTemplateForSelect" }, outputs: { onSave: "onSave", onDeleteTempldateNode: "onDeleteTempldateNode" }, host: { listeners: { "window:keydown": "onKeyDown($event)" } }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true, static: true }, { propertyName: "svgRef", first: true, predicate: ["svg"], descendants: true, static: true }, { propertyName: "wftemplatedetail", first: true, predicate: ["wftemplatedetail"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div\n #canvas\n class=\"workflow-canvas\"\n [class.connecting]=\"!!connectingFrom\"\n [class.dragging-point]=\"!!draggingPoint\"\n style=\"width: 100%; height: 100%\"\n (mousedown)=\"onMouseDownCanvas($event)\"\n (mousemove)=\"onMouseMoveCanvas($event)\"\n (mouseup)=\"onMouseUpCanvas($event)\"\n (click)=\"onClickCanvas($event)\"\n (wheel)=\"onWheelCanvas($event)\"\n>\n <!-- TOOLBAR -->\n <div class=\"toolbar\" (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\n <button nz-button nzSize=\"small\" nz-tooltip=\"Editor setting\" (click)=\"settingVisible = true\">\n <nz-icon nzType=\"setting\"></nz-icon>\n </button>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Infomation\" (click)=\"infoVisible = true\">\n <nz-icon nzType=\"info-circle\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Global Setting\" (click)=\"drawTemplateVisibel = true\">\n <nz-icon nzType=\"setting\"></nz-icon> G\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nzDanger [nzLoading]=\"!ready\" nz-tooltip=\"Save (Ctrl + S)\" (click)=\"save()\">\n <nz-icon nzType=\"save\"></nz-icon>\n </button>\n <button nz-button nzSize=\"small\" nz-tooltip=\"Th\u00EAm Template m\u1EDBi\" (click)=\"isModalVisible = true\">\n <nz-icon nzType=\"plus\" class=\"color-primary\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Move mode\"\n (click)=\"isMoveMode = true\"\n >\n <nz-icon><img src=\"/assets/icon/hand-palm.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"!isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Select mode\"\n (click)=\"isMoveMode = false\"\n >\n <nz-icon><img src=\"/assets/icon/cursor.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- UNDO / REDO -->\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"undoStack.length === 0\"\n nz-tooltip=\"Undo\"\n (click)=\"undo()\"\n >\n <nz-icon nzType=\"undo\"></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"redoStack.length === 0\"\n nz-tooltip=\"Redo\"\n (click)=\"redo()\"\n >\n <nz-icon nzType=\"redo\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ALIGN -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignLeft()\">\u27F8</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignCenter()\">\u2261</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignRight()\">\u27F9</button>\n <span class=\"divider\"></span>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignTop()\">\u21D1</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignMiddle()\">\u2550</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignBottom()\">\u21D3</button>\n <span class=\"divider\"></span>\n <!-- DISTRIBUTE -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 3\" (click)=\"distributeHorizontal()\">\n \u21C4\n </button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 3\" (click)=\"distributeVertical()\">\n \u21C5\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ZOOM -->\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"zoomOut()\" nz-tooltip=\"Zoom Out\">\n <nz-icon nzType=\"minus\"></nz-icon>\n </button>\n <span>{{ Math.round(zoom * 100) }}%</span>\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"zoomIn()\" nz-tooltip=\"Zoom In\">\n <nz-icon nzType=\"plus\"></nz-icon>\n </button>\n <span class=\"divider\"></span>\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"resetZoom()\" nz-tooltip=\"Reset Zoom (Ctrl+0)\">\n <nz-icon nzType=\"expand\"></nz-icon>\n </button>\n </div>\n\n <div\n class=\"canvas-content\"\n [class.panning]=\"isMoveMode\"\n [style.width.px]=\"getCanvasWidth()\"\n [style.height.px]=\"getCanvasHeight()\"\n [style.transform]=\"\n 'translate(' +\n templateCombine.editorOption.panX +\n 'px,' +\n templateCombine.editorOption.panY +\n 'px) scale(' +\n zoom +\n ')'\n \"\n >\n <!-- GRID -->\n <div *ngIf=\"wfcSetting.ShowGrid\" class=\"grid-layer\"></div>\n\n <!-- SVG EDGES -->\n <svg #svg class=\"edges-layer\" width=\"100%\" height=\"100%\" preserveAspectRatio=\"none\">\n <g>\n <!-- DEFS -->\n <defs>\n <filter id=\"edge-glow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n <feGaussianBlur stdDeviation=\"2\" result=\"blur\" />\n <feMerge>\n <feMergeNode in=\"blur\" />\n <feMergeNode in=\"SourceGraphic\" />\n </feMerge>\n </filter>\n\n <marker\n id=\"arrow-blue\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n <marker\n id=\"arrow-red\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n </defs>\n\n <!-- EDGES B\u00CCNH TH\u01AF\u1EDCNG -->\n <ng-container *ngFor=\"let e of normalEdges; let i = index\">\n <path class=\"edge\" [attr.id]=\"'edge-path-' + i\" [attr.d]=\"buildPath(e)\" marker-end=\"url(#arrow-blue)\"></path>\n\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseenter)=\"onMouseEnterEdge(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <!-- \u0110\u00E3 x\u00F3a *ngIf=\"e.RuleLineDetails?.length\" \u1EDF \u0111\u00E2y \u0111\u1EC3 text lu\u00F4n hi\u1EC7n -->\n <text\n class=\"edge-label\"\n style=\"fill: #1890ff; font-weight: 500\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.FromStage }} > {{ e.FromAction }}\n </text>\n </ng-container>\n\n <!-- EDGE \u0110ANG HOVER/SELECTED (HI\u1EC2N TH\u1ECA M\u00C0U \u0110\u1ECE) -->\n <ng-container *ngFor=\"let e of hoverEdges; let i = index\">\n <path\n class=\"edge red\"\n [attr.id]=\"'edge-path-hover-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-red)\"\n ></path>\n\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <text\n class=\"edge-label\"\n style=\"font-weight: bold; fill: red\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.FromStage }} > {{ e.FromAction }}\n </text>\n </ng-container>\n\n <!-- PREVIEW LINE (\u0110\u01AF\u1EDCNG N\u1ED0I \u0110ANG K\u00C9O) -->\n <path\n *ngIf=\"connectingFrom\"\n class=\"edge\"\n [attr.d]=\"buildPreviewPath()\"\n stroke-dasharray=\"5,5\"\n marker-end=\"url(#arrow-blue)\"\n ></path>\n </g>\n </svg>\n\n <!-- BOX V\u00D9NG CH\u1ECCN MULTI -->\n <div\n *ngIf=\"isSelecting && selectStart && selectEnd\"\n class=\"selection-box\"\n [style.left.px]=\"Math.min(selectStart.x, selectEnd.x)\"\n [style.top.px]=\"Math.min(selectStart.y, selectEnd.y)\"\n [style.width.px]=\"Math.abs(selectEnd.x - selectStart.x)\"\n [style.height.px]=\"Math.abs(selectEnd.y - selectStart.y)\"\n ></div>\n\n <!-- NODE (TEMPLATE) L\u1EDAP HI\u1EC2N TH\u1ECA TR\u00CAN C\u00D9NG -->\n @for (n of lstTemplateNode; track n.WF_Template_Id) {\n <nz-card\n class=\"workflow-node\"\n [attr.data-id]=\"n.Code\"\n [class.selected]=\"\n n == selectedTemplateNode || n == hoverTemplateNode || lstSelectedTemplateId.has(n.WF_Template_Id)\n \"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n) || isDraggingFrom(n) || isSelectedNode(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickNode(n)\"\n >\n <div class=\"title\" style=\"color: #1890ff; display: flex; justify-content: space-between; align-items: center\">\n <span>{{ n.Code }}</span>\n <nz-icon nzType=\"layout\" nzTheme=\"outline\"></nz-icon>\n </div>\n <div\n style=\"\n font-size: 12px;\n line-height: 1.2;\n font-weight: 500;\n height: 28px;\n overflow: hidden;\n text-overflow: ellipsis;\n \"\n >\n {{ n.Name || \"Ch\u01B0a c\u00F3 t\u00EAn\" }}\n </div>\n <div style=\"font-size: 10px; color: gray; margin-top: 4px\">\n {{ n.DocType }}\n </div>\n\n <!-- CONNECTOR \u0110\u1EC2 K\u00C9O D\u00C2Y -->\n <div class=\"connector connector-right\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n <div class=\"connector connector-left\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n </nz-card>\n }\n\n <!-- C\u00C1C \u0110I\u1EC2M WAYPOINT \u0110\u1EC2 B\u1EBA CONG D\u00C2Y CHU\u1ED8T -->\n @for (p of connectingPoints; track $index) {\n @if (p != draggingPoint) {\n <div\n class=\"waypoint\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n (contextmenu)=\"onRightClickPoint($event, hoverTemplateEdge!, $index)\"\n ></div>\n } @else {\n <div\n class=\"waypoint dragging\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n ></div>\n }\n }\n </div>\n</div>\n\n<!-- ==============================================\n 1. DRAWER: GLOBAL TEMPLATE SETTINGS \n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawTemplateTitle\"\n nzPlacement=\"right\"\n [nzWidth]=\"500\"\n [nzClosable]=\"false\"\n [nzVisible]=\"drawTemplateVisibel\"\n [nzFooter]=\"footerTplTemplate\"\n (nzOnClose)=\"drawTemplateVisibel = false\"\n>\n <ng-template #drawTemplateTitle> <nz-icon nzType=\"global\"></nz-icon> &nbsp; Quy tr\u00ECnh ph\u1ED1i h\u1EE3p </ng-template>\n <ng-container *nzDrawerContent>\n <!-- Gi\u1EEF nguy\u00EAn c\u00E1c th\u00F4ng tin chung to\u00E0n c\u1EE5c c\u1EE7a b\u1EA1n \u1EDF \u0111\u00E2y -->\n\n <extend-input [label]=\"'Code'\" [(_ngModel)]=\"templateCombine.Code\"></extend-input>\n <extend-input [label]=\"'Name'\" [(_ngModel)]=\"templateCombine.Name\"></extend-input>\n <extend-textarea [label]=\"'Description'\" [(_ngModel)]=\"templateCombine.Description\"></extend-textarea>\n <extend-checkbox [label]=\"'Active'\" [(_ngModel)]=\"templateCombine.IsActive\"></extend-checkbox>\n </ng-container>\n\n <ng-template #footerTplTemplate>\n <div nz-flex [nzGap]=\"6\" [nzJustify]=\"'end'\">\n <button nz-button nzDanger [nzLoading]=\"!ready\" (click)=\"save()\">Save</button>\n <button nz-button (click)=\"drawTemplateVisibel = false\">Close</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- ==============================================\n 2. DRAWER: NODE SETTINGS (CHI TI\u1EBET M\u1ED8T TEMPLATE)\n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawerTitleNode\"\n [nzPlacement]=\"selectedTemplateNode?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzVisible]=\"!!selectedTemplateNode\"\n [nzWidth]=\"'90vw'\"\n [nzClosable]=\"false\"\n [nzFooter]=\"footerTplNode\"\n (nzOnClose)=\"selectedTemplateNode = undefined\"\n>\n <ng-template #drawerTitleNode>\n <div nz-row nzJustify=\"space-between\">\n <span style=\"font-weight: bold; color: #1890ff\"\n ><nz-icon nzType=\"layout\"></nz-icon> TEMPLATE NODE: [{{ selectedTemplateNode?.Code }}]\n {{ selectedTemplateNode?.Name }}</span\n >\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"Chuy\u1EC3n v\u1ECB tr\u00ED Drawer\"\n (click)=\"\n selectedTemplateNode!.editorOption.drawerPosition =\n selectedTemplateNode!.editorOption.drawerPosition === 'left' ? 'right' : 'left'\n \"\n >\n <nz-icon nzType=\"swap\"></nz-icon>\n </button>\n </div>\n </ng-template>\n\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedTemplateNode\">\n <wf-template-detail #wftemplatedetail></wf-template-detail>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplNode>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedTemplateNode?.editorOption?.drawerPosition == 'left' ? 'start' : 'end'\"\n >\n <button nz-button nzDanger [nzLoading]=\"!ready\" (click)=\"wftemplatedetail.wfeditor.save()\">Save</button>\n <button nz-button (click)=\"selectedTemplateNode = undefined\">Close</button>\n <button nz-button nzDanger (click)=\"deleteTemplateNode()\">Delete Template node</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- ==============================================\n 3. DRAWER: EDGE SETTINGS (QU\u1EA2N L\u00DD QUY T\u1EAEC CHUY\u1EC2N TEMPLATE)\n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawerTitleEdge\"\n [nzPlacement]=\"selectedTemplateEdge?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzClosable]=\"false\"\n [nzWidth]=\"'450px'\"\n [nzVisible]=\"!!selectedTemplateEdge\"\n [nzFooter]=\"footerTplEdge\"\n (nzOnClose)=\"selectedTemplateEdge = undefined\"\n>\n <ng-template #drawerTitleEdge>\n <div nz-row nzJustify=\"space-between\">\n <span style=\"font-weight: bold; color: #ff4d4f\"><nz-icon nzType=\"swap-right\"></nz-icon> TRANSITION RULES </span>\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"Chuy\u1EC3n v\u1ECB tr\u00ED Drawer\"\n (click)=\"\n selectedTemplateEdge!.editorOption.drawerPosition =\n selectedTemplateEdge!.editorOption.drawerPosition === 'left' ? 'right' : 'left'\n \"\n >\n <nz-icon nzType=\"swap\"></nz-icon>\n </button>\n </div>\n </ng-template>\n\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedTemplateEdge\">\n <!-- Th\u00F4ng tin 2 \u0111\u1EA7u n\u1ED1i -->\n <div\n style=\"background: #fdf5f6; padding: 12px; border: 1px solid #ffa39e; border-radius: 6px; margin-bottom: 16px\"\n >\n <div style=\"font-size: 14px\">\n <strong style=\"display: inline-block; width: 70px; color: #555\">From:</strong>\n <span style=\"color: #1890ff; font-weight: 500\">\n [{{ getNode(selectedTemplateEdge.From_WF_Template_Id)?.Code }}]\n {{ getNode(selectedTemplateEdge.From_WF_Template_Id)?.Name }} > {{ selectedTemplateEdge.FromStage }} >\n {{ selectedTemplateEdge.FromAction }}\n </span>\n </div>\n <div style=\"font-size: 14px; margin-top: 8px\">\n <strong style=\"display: inline-block; width: 70px; color: #555\">Taget:</strong>\n <span style=\"color: #1890ff; font-weight: 500\">\n [{{ getNode(selectedTemplateEdge.To_WF_Template_Id)?.Code }}]\n {{ getNode(selectedTemplateEdge.To_WF_Template_Id)?.Name }} > {{ selectedTemplateEdge.ToStage }} >\n {{ selectedTemplateEdge.ToAction }}\n </span>\n </div>\n </div>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplEdge>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedTemplateEdge?.editorOption?.drawerPosition == 'left' ? 'start' : 'end'\"\n >\n <button nz-button nzDanger [nzLoading]=\"!ready\" (click)=\"save()\">Save Rules</button>\n <button\n nz-button\n nzDanger\n (click)=\"\n lstTemplateEdge.splice(lstTemplateEdge.indexOf(selectedTemplateEdge!), 1); selectedTemplateEdge = undefined\n \"\n >\n Delete Transition\n </button>\n <button nz-button (click)=\"selectedTemplateEdge = undefined\">Close</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- ==============================================\n 4. EDITOR SETTING & INFO\n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawSettingTitle\"\n nzPlacement=\"right\"\n [nzClosable]=\"false\"\n [nzVisible]=\"settingVisible\"\n (nzOnClose)=\"settingVisible = false\"\n>\n <ng-template #drawSettingTitle> <nz-icon nzType=\"setting\"></nz-icon> &nbsp; C\u00E0i \u0111\u1EB7t Editor </ng-template>\n <ng-container *nzDrawerContent>\n <div class=\"form-item-no-bottom\">\n <extend-checkbox\n [label]=\"'Hi\u1EC3n th\u1ECB L\u01B0\u1EDBi (Grid)'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"wfcSetting.ShowGrid\"\n ></extend-checkbox>\n </div>\n </ng-container>\n</nz-drawer>\n\n<nz-drawer\n [nzTitle]=\"drawInfoTitle\"\n nzPlacement=\"right\"\n [nzClosable]=\"false\"\n [nzVisible]=\"infoVisible\"\n (nzOnClose)=\"infoVisible = false\"\n>\n <ng-template #drawInfoTitle> <nz-icon nzType=\"info-circle\"></nz-icon> &nbsp; H\u01B0\u1EDBng d\u1EABn (Infomation) </ng-template>\n <ng-container *nzDrawerContent>\n <p>\n <strong>1. C\u00E1c th\u00E0nh ph\u1EA7n:</strong> C\u00E1c \u00F4 ch\u1EEF nh\u1EADt l\u00E0 Template (Quy tr\u00ECnh nh\u1ECF), c\u00E1c \u0111\u01B0\u1EDDng n\u1ED1i l\u00E0 Transition Rule\n (Quy t\u1EAFc chuy\u1EC3n quy tr\u00ECnh).\n </p>\n <p><strong>2. C\u00E1ch n\u1ED1i 2 Template:</strong></p>\n <ul>\n <li>Click ch\u1EA5m cam b\u00EAn ph\u1EA3i Template A, sau \u0111\u00F3 k\u00E9o v\u00E0 click v\u00E0o Template B \u0111\u1EC3 t\u1EA1o Rule n\u1ED1i.</li>\n <li>C\u00F3 th\u1EC3 click nhi\u1EC1u \u0111i\u1EC3m trong l\u00FAc k\u00E9o \u0111\u1EC3 b\u1EBB \u0111\u01B0\u1EDDng cong tu\u1EF3 \u00FD (Waypoint).</li>\n <li>Click \u0111\u00FAp v\u00E0o c\u1EA1nh (\u0111\u01B0\u1EDDng n\u1ED1i) \u0111ang c\u00F3 \u0111\u1EC3 t\u1EA1o th\u00EAm m\u1ED9t \u0111i\u1EC3m b\u1EBB cong m\u1EDBi.</li>\n <li>Gi\u1EEF v\u00E0 k\u00E9o \u0111i\u1EC3m b\u1EBB cong \u0111\u1EC3 tu\u1EF3 ch\u1EC9nh \u0111\u01B0\u1EDDng \u0111i. Chu\u1ED9t ph\u1EA3i v\u00E0o \u0111i\u1EC3m \u0111\u00F3 \u0111\u1EC3 x\u00F3a n\u00F3.</li>\n </ul>\n <p>\n <strong>3. Qu\u1EA3n l\u00FD Rule:</strong> Click v\u00E0o \u0111\u01B0\u1EDDng n\u1ED1i gi\u1EEFa 2 Node \u0111\u1EC3 c\u1EA5u h\u00ECnh c\u00E1c lu\u1ED3ng th\u1EF1c thi (Stored, Ph\u00E2n\n quy\u1EC1n, G\u1EEDi mail).\n </p>\n </ng-container>\n</nz-drawer>\n\n<nz-modal\n [(nzVisible)]=\"isModalVisible\"\n nzTitle=\"Add template node\"\n [nzWidth]=\"600\"\n (nzOnCancel)=\"isModalVisible = false\"\n (nzOnOk)=\"addTemplateNodes()\"\n nzOkText=\"Add\"\n nzOkDanger\n nzCancelText=\"Cancel\"\n nzMaskClosable=\"false\"\n>\n <ng-container *nzModalContent>\n <extend-select\n label=\"Template\"\n [lstItem]=\"lstTemplateForSelect\"\n [displayField]=\"'Name'\"\n [multiple]=\"true\"\n [(_ngModel)]=\"lstTemplateSelected\"\n ></extend-select>\n </ng-container>\n</nz-modal>\n", styles: ["@charset \"UTF-8\";::ng-deep .workflow-wrapper{border:solid 1px lightgray;overflow:hidden;width:100%}.workflow-canvas{position:relative;background:#f0f2f5;cursor:default;overflow:hidden;outline:1px dashed rgba(0,0,0,.1)}.workflow-canvas .edges-layer{position:absolute;inset:0;width:100%;height:100%;z-index:1}.workflow-canvas .edges-layer path{stroke-width:2;fill:none}.canvas-content{transform-origin:0 0;width:100%;height:100%;transition:transform .05s linear}.canvas-content{outline:1px dashed red}.canvas-content.panning{cursor:grab}.canvas-content.panning:active{cursor:grabbing}.workflow-canvas.panning{cursor:grab}.workflow-canvas.panning:active{cursor:grabbing}.workflow-canvas.connecting,.workflow-canvas.connecting .workflow-node{cursor:crosshair}.workflow-node{position:absolute;width:160px;cursor:grab;-webkit-user-select:none;user-select:none;z-index:2}.workflow-node:active{cursor:grabbing}.workflow-node.connecting-source,.workflow-node.selected,.workflow-node:hover:not(.workflow-node-start,.workflow-node-end){outline:2px dashed #1890ff}.workflow-node .title{font-weight:600;margin-bottom:6px}.workflow-node-start{width:0px}.workflow-node-start.connecting-source,.workflow-node-start.selected,.workflow-node-start:hover{outline:unset}.workflow-node-start.connecting-source nz-tag,.workflow-node-start.selected nz-tag,.workflow-node-start:hover nz-tag{outline:2px dashed}.workflow-node-start nz-tag{position:relative;top:45px;right:35px}.workflow-node-end{width:0px}.workflow-node-end.connecting-source,.workflow-node-end.selected,.workflow-node-end:hover{outline:unset}.workflow-node-end.connecting-source nz-tag,.workflow-node-end.selected nz-tag,.workflow-node-end:hover nz-tag{outline:2px dashed}.workflow-node-end nz-tag{position:relative;top:45px;right:32px}.connector{position:absolute;top:39px;width:12px;height:12px;background:#1890ff;border-radius:50%;transform:translateY(-50%);cursor:crosshair;transition:box-shadow .15s ease-out,transform .15s ease-out}.connector:hover{box-shadow:0 0 0 3px #1890ff4d;transform:translateY(-50%) scale(1.15)}.connector-right{right:-8px;background:orange}.connector-right.reverse,.connector-left{left:-8px}.connector-left.reverse{left:unset;right:-8px}.connector-start{width:16px;height:16px;right:-8px;background:green;box-shadow:0 0 0 3px #1890ff4d}.connector-end{width:16px;height:16px;left:-8px;background:#000;box-shadow:0 0 0 3px #1890ff4d}.edge{cursor:pointer;stroke:#1890ff;stroke-linecap:round;stroke-linejoin:round;stroke-width:2;fill:none;transition:stroke .15s ease}.edge-hit{stroke:transparent;stroke-width:18px!important;fill:none;cursor:pointer}.edge-hit:hover+.edge{stroke:#ff4d4f;stroke-width:2}.workflow-canvas.dragging-point .edge-hit{pointer-events:none}.edge:hover+.edge-label{fill:#1890ff;font-weight:500}.edge-label{font-size:12px;fill:#555;pointer-events:none;-webkit-user-select:none;user-select:none}.blue{stroke:#1890ff!important}.red{stroke:#ff4d4f!important;box-shadow:0 0 0 3px #1890ff4d!important}.workflow-svg{background:transparent;overflow:visible}.waypoint{position:absolute;width:10px;height:10px;background:#ff4d4f;border-radius:50%;transform:translate(-50%,-50%) scale(1);cursor:move;z-index:1;transition:transform .12s ease-out,background-color .12s ease-out,box-shadow .12s ease-out}.waypoint:hover{background:#ff7875;transform:translate(-50%,-50%) scale(1.25);box-shadow:0 0 0 4px #ff787559}.waypoint.dragging{transition:none;transform:translate(-50%,-50%) scale(1.15);pointer-events:none}.workflow-canvas.dragging-point svg{cursor:grabbing}.selection-box{position:absolute;border:1px dashed #1890ff;background:#1890ff1a;pointer-events:none}.toolbar{position:absolute;top:8px;left:8px;display:flex;gap:4px;padding:6px;background:#fff;border-radius:6px;box-shadow:0 2px 8px #00000026;z-index:100}.toolbar .divider{width:1px;background:#e5e5e5;margin:0 2px}nz-tag.selected{outline:2px dashed #1890ff}.grid-layer{position:absolute;inset:0;pointer-events:none;z-index:0;background-image:radial-gradient(rgba(0,0,0,.08) 1px,transparent 1px);background-size:20px 20px}.grid-layer{background-image:linear-gradient(to right,rgba(0,0,0,.06) 1px,transparent 1px),linear-gradient(to bottom,rgba(0,0,0,.06) 1px,transparent 1px);background-size:20px 20px}.editable-tag{background:#fff;border-style:dashed}::ng-deep .minimap,.minimap-combine{position:absolute;width:180px;height:125px;top:0;right:0;background-color:#eee;border:1px solid #aaa;opacity:.9;z-index:1}::ng-deep .minimap{position:absolute;width:200px;height:140px;top:8px;right:8px;background-color:#f8f9fa;border:1px solid #d9d9d9;border-radius:8px;box-shadow:0 4px 12px #0000001a;overflow:hidden;z-index:100;-webkit-user-select:none;user-select:none}::ng-deep .minimap-node{position:absolute;background-color:#bfbfbf;border-radius:2px}::ng-deep .minimap-node-round{position:absolute;background-color:#bfbfbf;border-radius:50%}::ng-deep .minimap-node-round-start{background-color:#52c41a}::ng-deep .minimap-node-round-end{background-color:#ff4d4f}::ng-deep .minimap-viewport{position:absolute;box-sizing:border-box;background-color:#1890ff26;border:1.5px solid #1890ff;border-radius:4px;z-index:2;cursor:grab;transition:none}::ng-deep .minimap-viewport.grabbing,::ng-deep .minimap-viewport:active{cursor:grabbing;background-color:#1890ff40}::ng-deep .has-floating-label.floating-label{position:relative;padding-top:14px}::ng-deep .has-floating-label nz-form-item nz-form-label{position:absolute;top:12px;left:13px;transform:translateY(-50%);background:linear-gradient(to bottom,var(--form-bg-color, #ffffff) 80%,#ffffff 80%);z-index:1;height:auto;line-height:normal;padding:0 4px}::ng-deep .has-floating-label nz-form-item nz-form-label label{font-size:12px;color:var(--darkgray, #565656);font-weight:700;height:auto;line-height:normal;padding:0;display:flex;align-items:center}::ng-deep .has-floating-label .full-width{width:100%}.has-floating-label.floating-label nz-form-item:has(.ant-select-disabled) nz-form-label,.has-floating-label.floating-label nz-form-item:has(input[disabled]) nz-form-label,.has-floating-label.floating-label nz-form-item:has(.ant-input-disabled) nz-form-label{background:linear-gradient(to bottom,var(--form-bg-color, #ffffff) 60%,#f5f5f5 50%)}.has-floating-label.floating-label nz-form-item:has(.ant-select-disabled) nz-form-label label,.has-floating-label.floating-label nz-form-item:has(input[disabled]) nz-form-label label,.has-floating-label.floating-label nz-form-item:has(.ant-input-disabled) nz-form-label label{color:#bfbfbf}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: NzCardModule }, { kind: "component", type: i3$5.NzCardComponent, selector: "nz-card", inputs: ["nzBordered", "nzLoading", "nzHoverable", "nzBodyStyle", "nzCover", "nzActions", "nzType", "nzSize", "nzTitle", "nzExtra"], exportAs: ["nzCard"] }, { kind: "ngmodule", type: NzDrawerModule }, { kind: "component", type: i3$6.NzDrawerComponent, selector: "nz-drawer", inputs: ["nzContent", "nzCloseIcon", "nzClosable", "nzMaskClosable", "nzMask", "nzCloseOnNavigation", "nzNoAnimation", "nzKeyboard", "nzTitle", "nzExtra", "nzFooter", "nzPlacement", "nzSize", "nzMaskStyle", "nzBodyStyle", "nzWrapClassName", "nzWidth", "nzHeight", "nzZIndex", "nzOffsetX", "nzOffsetY", "nzVisible"], outputs: ["nzOnViewInit", "nzOnClose", "nzVisibleChange"], exportAs: ["nzDrawer"] }, { kind: "directive", type: i3$6.NzDrawerContentDirective, selector: "[nzDrawerContent]", exportAs: ["nzDrawerContent"] }, { kind: "ngmodule", type: NzTagModule }, { kind: "ngmodule", type: NzRadioModule }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1$2.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "component", type: Box, selector: "box", inputs: ["display", "width", "height"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i2$2.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i3$2.ɵNzTransitionPatchDirective, selector: "[nz-button], nz-button-group, [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i4$1.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }, { kind: "ngmodule", type: NzToolTipModule }, { kind: "directive", type: i8.NzTooltipDirective, selector: "[nz-tooltip]", inputs: ["nzTooltipTitle", "nzTooltipTitleContext", "nz-tooltip", "nzTooltipTrigger", "nzTooltipPlacement", "nzTooltipOrigin", "nzTooltipVisible", "nzTooltipMouseEnterDelay", "nzTooltipMouseLeaveDelay", "nzTooltipOverlayClassName", "nzTooltipOverlayStyle", "nzTooltipArrowPointAtCenter", "cdkConnectedOverlayPush", "nzTooltipColor"], outputs: ["nzTooltipVisibleChange"], exportAs: ["nzTooltip"] }, { kind: "component", type: ExtendInput, selector: "extend-input", inputs: ["label", "floatingLabel", "placeHolder", "labelAlign", "inputClass", "labelSpan", "labelFlex", "inputFlex", "showClear", "disabled", "readOnly", "required", "noBottom", "selectModeType", "autocomplete", "autofocus", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "size", "displayField", "valueField", "formData", "controlName", "_ngModel", "isSubmited"], outputs: ["_ngModelChange", "onclickClearIcon", "onenter"] }, { kind: "component", type: ExtendSelectComponent, selector: "extend-select", inputs: ["label", "floatingLabel", "placeHolder", "labelAlign", "dropdownMatchSelectWidth", "labelSpan", "labelFlex", "disabled", "required", "noBottom", "multiple", "showSelectAll", "maxTagCount", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "size", "lstItem", "displayField", "displayFields", "info", "valueField", "formData", "controlName", "_ngModel", "isSubmited"], outputs: ["_ngModelChange", "itemChange", "onFocus"] }, { kind: "component", type: ExtendCheckbox, selector: "extend-checkbox", inputs: ["label", "labelSpan", "labelFlex", "paddingTop", "disabled", "formData", "controlName", "valueType", "_ngModel"], outputs: ["_ngModelChange"] }, { kind: "component", type: ExtendTextArea, selector: "extend-textarea", inputs: ["label", "placeHolder", "labelAlign", "floatingLabel", "displayInline", "formItemNoButtom", "labelSpan", "labelFlex", "inputFlex", "disabled", "required", "noBottom", "selectModeType", "inputClass", "size", "isSubmited", "minRows", "maxRows", "lstItem", "displayField", "valueField", "formData", "controlName", "_ngModel", "isTouched", "inputErrorMessage", "errorMessages"], outputs: ["_ngModelChange"] }, { kind: "ngmodule", type: NzInputModule }, { kind: "ngmodule", type: NzGridModule }, { kind: "directive", type: i2$1.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "ngmodule", type: NzFlexModule }, { kind: "directive", type: i3$3.NzFlexDirective, selector: "[nz-flex],nz-flex", inputs: ["nzVertical", "nzJustify", "nzAlign", "nzGap", "nzWrap", "nzFlex"], exportAs: ["nzFlex"] }, { kind: "ngmodule", type: NzTableModule }, { kind: "ngmodule", type: NzDividerModule }, { kind: "ngmodule", type: NzAutocompleteModule }, { kind: "component", type: NzModalComponent, selector: "nz-modal", inputs: ["nzMask", "nzMaskClosable", "nzCloseOnNavigation", "nzVisible", "nzClosable", "nzOkLoading", "nzOkDisabled", "nzCancelDisabled", "nzCancelLoading", "nzKeyboard", "nzNoAnimation", "nzCentered", "nzDraggable", "nzContent", "nzFooter", "nzZIndex", "nzWidth", "nzWrapClassName", "nzClassName", "nzStyle", "nzTitle", "nzCloseIcon", "nzMaskStyle", "nzBodyStyle", "nzOkText", "nzCancelText", "nzOkType", "nzOkDanger", "nzIconType", "nzModalType", "nzAutofocus", "nzOnOk", "nzOnCancel"], outputs: ["nzOnOk", "nzOnCancel", "nzAfterOpen", "nzAfterClose", "nzVisibleChange"], exportAs: ["nzModal"] }, { kind: "directive", type: NzModalContentDirective, selector: "[nzModalContent]", exportAs: ["nzModalContent"] }, { kind: "component", type: WF_TemplateDetail, selector: "wf-template-detail" }] });
19460
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: WF_Template_CombineEditorComponent, isStandalone: true, selector: "app-workflow-combine-editor", inputs: { lstTemplateForSelect: "lstTemplateForSelect" }, outputs: { onSave: "onSave", onDeleteTempldateNode: "onDeleteTempldateNode" }, host: { listeners: { "window:keydown": "onKeyDown($event)" } }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true, static: true }, { propertyName: "svgRef", first: true, predicate: ["svg"], descendants: true, static: true }, { propertyName: "wftemplatedetail", first: true, predicate: ["wftemplatedetail"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div\n #canvas\n class=\"workflow-canvas\"\n [class.connecting]=\"!!connectingFrom\"\n [class.dragging-point]=\"!!draggingPoint\"\n style=\"width: 100%; height: 100%\"\n (mousedown)=\"onMouseDownCanvas($event)\"\n (mousemove)=\"onMouseMoveCanvas($event)\"\n (mouseup)=\"onMouseUpCanvas($event)\"\n (click)=\"onClickCanvas($event)\"\n (wheel)=\"onWheelCanvas($event)\"\n>\n <!-- TOOLBAR -->\n <div class=\"toolbar\" (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\n <button nz-button nzSize=\"small\" nz-tooltip=\"Editor setting\" (click)=\"settingVisible = true\">\n <nz-icon nzType=\"setting\"></nz-icon>\n </button>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Infomation\" (click)=\"infoVisible = true\">\n <nz-icon nzType=\"info-circle\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Global Setting\" (click)=\"drawTemplateVisibel = true\">\n <nz-icon nzType=\"setting\"></nz-icon> G\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nzDanger [nzLoading]=\"!ready\" nz-tooltip=\"Save (Ctrl + S)\" (click)=\"save()\">\n <nz-icon nzType=\"save\"></nz-icon>\n </button>\n <button nz-button nzSize=\"small\" nz-tooltip=\"Th\u00EAm Template m\u1EDBi\" (click)=\"isModalVisible = true\">\n <nz-icon nzType=\"plus\" class=\"color-primary\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Move mode\"\n (click)=\"isMoveMode = true\"\n >\n <nz-icon><img src=\"/assets/icon/hand-palm.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"!isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Select mode\"\n (click)=\"isMoveMode = false\"\n >\n <nz-icon><img src=\"/assets/icon/cursor.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- UNDO / REDO -->\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"undoStack.length === 0\"\n nz-tooltip=\"Undo\"\n (click)=\"undo()\"\n >\n <nz-icon nzType=\"undo\"></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"redoStack.length === 0\"\n nz-tooltip=\"Redo\"\n (click)=\"redo()\"\n >\n <nz-icon nzType=\"redo\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ALIGN -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignLeft()\">\u27F8</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignCenter()\">\u2261</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignRight()\">\u27F9</button>\n <span class=\"divider\"></span>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignTop()\">\u21D1</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignMiddle()\">\u2550</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignBottom()\">\u21D3</button>\n <span class=\"divider\"></span>\n <!-- DISTRIBUTE -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 3\" (click)=\"distributeHorizontal()\">\n \u21C4\n </button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 3\" (click)=\"distributeVertical()\">\n \u21C5\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ZOOM -->\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"zoomOut()\" nz-tooltip=\"Zoom Out\">\n <nz-icon nzType=\"minus\"></nz-icon>\n </button>\n <span>{{ Math.round(zoom * 100) }}%</span>\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"zoomIn()\" nz-tooltip=\"Zoom In\">\n <nz-icon nzType=\"plus\"></nz-icon>\n </button>\n <span class=\"divider\"></span>\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"resetZoom()\" nz-tooltip=\"Reset Zoom (Ctrl+0)\">\n <nz-icon nzType=\"expand\"></nz-icon>\n </button>\n </div>\n\n <div\n class=\"canvas-content\"\n [class.panning]=\"isMoveMode\"\n [style.width.px]=\"getCanvasWidth()\"\n [style.height.px]=\"getCanvasHeight()\"\n [style.transform]=\"\n 'translate(' +\n templateCombine.editorOption.panX +\n 'px,' +\n templateCombine.editorOption.panY +\n 'px) scale(' +\n zoom +\n ')'\n \"\n >\n <!-- GRID -->\n <div *ngIf=\"wfcSetting.ShowGrid\" class=\"grid-layer\"></div>\n\n <!-- SVG EDGES -->\n <svg #svg class=\"edges-layer\" width=\"100%\" height=\"100%\" preserveAspectRatio=\"none\">\n <g>\n <!-- DEFS -->\n <defs>\n <filter id=\"edge-glow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n <feGaussianBlur stdDeviation=\"2\" result=\"blur\" />\n <feMerge>\n <feMergeNode in=\"blur\" />\n <feMergeNode in=\"SourceGraphic\" />\n </feMerge>\n </filter>\n\n <marker\n id=\"arrow-blue\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n <marker\n id=\"arrow-red\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n </defs>\n\n <!-- EDGES B\u00CCNH TH\u01AF\u1EDCNG -->\n <ng-container *ngFor=\"let e of normalEdges; let i = index\">\n <path class=\"edge\" [attr.id]=\"'edge-path-' + i\" [attr.d]=\"buildPath(e)\" marker-end=\"url(#arrow-blue)\"></path>\n\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseenter)=\"onMouseEnterEdge(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <!-- \u0110\u00E3 x\u00F3a *ngIf=\"e.RuleLineDetails?.length\" \u1EDF \u0111\u00E2y \u0111\u1EC3 text lu\u00F4n hi\u1EC7n -->\n <text\n class=\"edge-label\"\n style=\"fill: #1890ff; font-weight: 500\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.FromStage }} / {{ e.FromAction }} > {{ e.ToStage }} / {{ e.ToAction }}\n </text>\n </ng-container>\n\n <!-- EDGE \u0110ANG HOVER/SELECTED (HI\u1EC2N TH\u1ECA M\u00C0U \u0110\u1ECE) -->\n <ng-container *ngFor=\"let e of hoverEdges; let i = index\">\n <path\n class=\"edge red\"\n [attr.id]=\"'edge-path-hover-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-red)\"\n ></path>\n\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <text\n class=\"edge-label\"\n style=\"font-weight: bold; fill: red\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.FromStage }} / {{ e.FromAction }} > {{ e.ToStage }} / {{ e.ToAction }}\n </text>\n </ng-container>\n\n <!-- PREVIEW LINE (\u0110\u01AF\u1EDCNG N\u1ED0I \u0110ANG K\u00C9O) -->\n <path\n *ngIf=\"connectingFrom\"\n class=\"edge\"\n [attr.d]=\"buildPreviewPath()\"\n stroke-dasharray=\"5,5\"\n marker-end=\"url(#arrow-blue)\"\n ></path>\n </g>\n </svg>\n\n <!-- BOX V\u00D9NG CH\u1ECCN MULTI -->\n <div\n *ngIf=\"isSelecting && selectStart && selectEnd\"\n class=\"selection-box\"\n [style.left.px]=\"Math.min(selectStart.x, selectEnd.x)\"\n [style.top.px]=\"Math.min(selectStart.y, selectEnd.y)\"\n [style.width.px]=\"Math.abs(selectEnd.x - selectStart.x)\"\n [style.height.px]=\"Math.abs(selectEnd.y - selectStart.y)\"\n ></div>\n\n <!-- NODE (TEMPLATE) L\u1EDAP HI\u1EC2N TH\u1ECA TR\u00CAN C\u00D9NG -->\n @for (n of lstTemplateNode; track n.WF_Template_Id) {\n <nz-card\n class=\"workflow-node\"\n [attr.data-id]=\"n.Code\"\n [class.selected]=\"\n n == selectedTemplateNode || n == hoverTemplateNode || lstSelectedTemplateId.has(n.WF_Template_Id)\n \"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n) || isDraggingFrom(n) || isSelectedNode(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickNode(n)\"\n >\n <div class=\"title\" style=\"color: #1890ff; display: flex; justify-content: space-between; align-items: center\">\n <span>{{ n.Code }}</span>\n <nz-icon nzType=\"layout\" nzTheme=\"outline\"></nz-icon>\n </div>\n <div\n style=\"\n font-size: 12px;\n line-height: 1.2;\n font-weight: 500;\n height: 28px;\n overflow: hidden;\n text-overflow: ellipsis;\n \"\n >\n {{ n.Name || \"Ch\u01B0a c\u00F3 t\u00EAn\" }}\n </div>\n <div style=\"font-size: 10px; color: gray; margin-top: 4px\">\n {{ n.DocType }}\n </div>\n\n <!-- CONNECTOR \u0110\u1EC2 K\u00C9O D\u00C2Y -->\n <div class=\"connector connector-right\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n <div class=\"connector connector-left\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n </nz-card>\n }\n\n <!-- C\u00C1C \u0110I\u1EC2M WAYPOINT \u0110\u1EC2 B\u1EBA CONG D\u00C2Y CHU\u1ED8T -->\n @for (p of connectingPoints; track $index) {\n @if (p != draggingPoint) {\n <div\n class=\"waypoint\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n (contextmenu)=\"onRightClickPoint($event, hoverTemplateEdge!, $index)\"\n ></div>\n } @else {\n <div\n class=\"waypoint dragging\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n ></div>\n }\n }\n </div>\n</div>\n\n<!-- ==============================================\n 1. DRAWER: GLOBAL TEMPLATE SETTINGS \n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawTemplateTitle\"\n nzPlacement=\"right\"\n [nzWidth]=\"500\"\n [nzClosable]=\"false\"\n [nzVisible]=\"drawTemplateVisibel\"\n [nzFooter]=\"footerTplTemplate\"\n (nzOnClose)=\"drawTemplateVisibel = false\"\n>\n <ng-template #drawTemplateTitle> <nz-icon nzType=\"global\"></nz-icon> &nbsp; Quy tr\u00ECnh ph\u1ED1i h\u1EE3p </ng-template>\n <ng-container *nzDrawerContent>\n <!-- Gi\u1EEF nguy\u00EAn c\u00E1c th\u00F4ng tin chung to\u00E0n c\u1EE5c c\u1EE7a b\u1EA1n \u1EDF \u0111\u00E2y -->\n\n <extend-input [label]=\"'Code'\" [(_ngModel)]=\"templateCombine.Code\"></extend-input>\n <extend-input [label]=\"'Name'\" [(_ngModel)]=\"templateCombine.Name\"></extend-input>\n <extend-textarea [label]=\"'Description'\" [(_ngModel)]=\"templateCombine.Description\"></extend-textarea>\n <extend-checkbox [label]=\"'Active'\" [(_ngModel)]=\"templateCombine.IsActive\"></extend-checkbox>\n </ng-container>\n\n <ng-template #footerTplTemplate>\n <div nz-flex [nzGap]=\"6\" [nzJustify]=\"'end'\">\n <button nz-button nzDanger [nzLoading]=\"!ready\" (click)=\"save()\">Save</button>\n <button nz-button (click)=\"drawTemplateVisibel = false\">Close</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- ==============================================\n 2. DRAWER: NODE SETTINGS (CHI TI\u1EBET M\u1ED8T TEMPLATE)\n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawerTitleNode\"\n [nzPlacement]=\"selectedTemplateNode?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzVisible]=\"!!selectedTemplateNode\"\n [nzWidth]=\"'90vw'\"\n [nzClosable]=\"false\"\n [nzFooter]=\"footerTplNode\"\n (nzOnClose)=\"selectedTemplateNode = undefined\"\n>\n <ng-template #drawerTitleNode>\n <div nz-row nzJustify=\"space-between\">\n <span style=\"font-weight: bold; color: #1890ff\"\n ><nz-icon nzType=\"layout\"></nz-icon> TEMPLATE NODE: [{{ selectedTemplateNode?.Code }}]\n {{ selectedTemplateNode?.Name }}</span\n >\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"Chuy\u1EC3n v\u1ECB tr\u00ED Drawer\"\n (click)=\"\n selectedTemplateNode!.editorOption.drawerPosition =\n selectedTemplateNode!.editorOption.drawerPosition === 'left' ? 'right' : 'left'\n \"\n >\n <nz-icon nzType=\"swap\"></nz-icon>\n </button>\n </div>\n </ng-template>\n\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedTemplateNode\">\n <wf-template-detail #wftemplatedetail></wf-template-detail>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplNode>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedTemplateNode?.editorOption?.drawerPosition == 'left' ? 'start' : 'end'\"\n >\n <button nz-button nzDanger [nzLoading]=\"!ready\" (click)=\"wftemplatedetail.wfeditor.save()\">Save</button>\n <button nz-button (click)=\"selectedTemplateNode = undefined\">Close</button>\n <button nz-button nzDanger (click)=\"deleteTemplateNode()\">Delete Template node</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- ==============================================\n 3. DRAWER: EDGE SETTINGS (QU\u1EA2N L\u00DD QUY T\u1EAEC CHUY\u1EC2N TEMPLATE)\n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawerTitleEdge\"\n [nzPlacement]=\"selectedTemplateEdge?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzClosable]=\"false\"\n [nzWidth]=\"'450px'\"\n [nzVisible]=\"!!selectedTemplateEdge\"\n [nzFooter]=\"footerTplEdge\"\n (nzOnClose)=\"selectedTemplateEdge = undefined\"\n>\n <ng-template #drawerTitleEdge>\n <div nz-row nzJustify=\"space-between\">\n <span style=\"font-weight: bold; color: #ff4d4f\"><nz-icon nzType=\"swap-right\"></nz-icon> TRANSITION RULES </span>\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"Chuy\u1EC3n v\u1ECB tr\u00ED Drawer\"\n (click)=\"\n selectedTemplateEdge!.editorOption.drawerPosition =\n selectedTemplateEdge!.editorOption.drawerPosition === 'left' ? 'right' : 'left'\n \"\n >\n <nz-icon nzType=\"swap\"></nz-icon>\n </button>\n </div>\n </ng-template>\n\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedTemplateEdge\">\n <!-- Th\u00F4ng tin 2 \u0111\u1EA7u n\u1ED1i -->\n <div\n style=\"background: #fdf5f6; padding: 12px; border: 1px solid #ffa39e; border-radius: 6px; margin-bottom: 16px\"\n >\n <div style=\"font-size: 14px\">\n <strong style=\"display: inline-block; width: 70px; color: #555\">From:</strong>\n <span style=\"color: #1890ff; font-weight: 500\">\n [{{ getNode(selectedTemplateEdge.From_WF_Template_Id)?.Code }}]\n {{ getNode(selectedTemplateEdge.From_WF_Template_Id)?.Name }} > {{ selectedTemplateEdge.FromStage }} >\n {{ selectedTemplateEdge.FromAction }}\n </span>\n </div>\n <div style=\"font-size: 14px; margin-top: 8px\">\n <strong style=\"display: inline-block; width: 70px; color: #555\">Taget:</strong>\n <span style=\"color: #1890ff; font-weight: 500\">\n [{{ getNode(selectedTemplateEdge.To_WF_Template_Id)?.Code }}]\n {{ getNode(selectedTemplateEdge.To_WF_Template_Id)?.Name }} > {{ selectedTemplateEdge.ToStage }} >\n {{ selectedTemplateEdge.ToAction }}\n </span>\n </div>\n </div>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplEdge>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedTemplateEdge?.editorOption?.drawerPosition == 'left' ? 'start' : 'end'\"\n >\n <button nz-button nzDanger [nzLoading]=\"!ready\" (click)=\"save()\">Save Rules</button>\n <button\n nz-button\n nzDanger\n (click)=\"\n lstTemplateEdge.splice(lstTemplateEdge.indexOf(selectedTemplateEdge!), 1); selectedTemplateEdge = undefined\n \"\n >\n Delete Transition\n </button>\n <button nz-button (click)=\"selectedTemplateEdge = undefined\">Close</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- ==============================================\n 4. EDITOR SETTING & INFO\n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawSettingTitle\"\n nzPlacement=\"right\"\n [nzClosable]=\"false\"\n [nzVisible]=\"settingVisible\"\n (nzOnClose)=\"settingVisible = false\"\n>\n <ng-template #drawSettingTitle> <nz-icon nzType=\"setting\"></nz-icon> &nbsp; C\u00E0i \u0111\u1EB7t Editor </ng-template>\n <ng-container *nzDrawerContent>\n <div class=\"form-item-no-bottom\">\n <extend-checkbox\n [label]=\"'Hi\u1EC3n th\u1ECB L\u01B0\u1EDBi (Grid)'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"wfcSetting.ShowGrid\"\n ></extend-checkbox>\n </div>\n </ng-container>\n</nz-drawer>\n\n<nz-drawer\n [nzTitle]=\"drawInfoTitle\"\n nzPlacement=\"right\"\n [nzClosable]=\"false\"\n [nzVisible]=\"infoVisible\"\n (nzOnClose)=\"infoVisible = false\"\n>\n <ng-template #drawInfoTitle> <nz-icon nzType=\"info-circle\"></nz-icon> &nbsp; H\u01B0\u1EDBng d\u1EABn (Infomation) </ng-template>\n <ng-container *nzDrawerContent>\n <p>\n <strong>1. C\u00E1c th\u00E0nh ph\u1EA7n:</strong> C\u00E1c \u00F4 ch\u1EEF nh\u1EADt l\u00E0 Template (Quy tr\u00ECnh nh\u1ECF), c\u00E1c \u0111\u01B0\u1EDDng n\u1ED1i l\u00E0 Transition Rule\n (Quy t\u1EAFc chuy\u1EC3n quy tr\u00ECnh).\n </p>\n <p><strong>2. C\u00E1ch n\u1ED1i 2 Template:</strong></p>\n <ul>\n <li>Click ch\u1EA5m cam b\u00EAn ph\u1EA3i Template A, sau \u0111\u00F3 k\u00E9o v\u00E0 click v\u00E0o Template B \u0111\u1EC3 t\u1EA1o Rule n\u1ED1i.</li>\n <li>C\u00F3 th\u1EC3 click nhi\u1EC1u \u0111i\u1EC3m trong l\u00FAc k\u00E9o \u0111\u1EC3 b\u1EBB \u0111\u01B0\u1EDDng cong tu\u1EF3 \u00FD (Waypoint).</li>\n <li>Click \u0111\u00FAp v\u00E0o c\u1EA1nh (\u0111\u01B0\u1EDDng n\u1ED1i) \u0111ang c\u00F3 \u0111\u1EC3 t\u1EA1o th\u00EAm m\u1ED9t \u0111i\u1EC3m b\u1EBB cong m\u1EDBi.</li>\n <li>Gi\u1EEF v\u00E0 k\u00E9o \u0111i\u1EC3m b\u1EBB cong \u0111\u1EC3 tu\u1EF3 ch\u1EC9nh \u0111\u01B0\u1EDDng \u0111i. Chu\u1ED9t ph\u1EA3i v\u00E0o \u0111i\u1EC3m \u0111\u00F3 \u0111\u1EC3 x\u00F3a n\u00F3.</li>\n </ul>\n <p>\n <strong>3. Qu\u1EA3n l\u00FD Rule:</strong> Click v\u00E0o \u0111\u01B0\u1EDDng n\u1ED1i gi\u1EEFa 2 Node \u0111\u1EC3 c\u1EA5u h\u00ECnh c\u00E1c lu\u1ED3ng th\u1EF1c thi (Stored, Ph\u00E2n\n quy\u1EC1n, G\u1EEDi mail).\n </p>\n </ng-container>\n</nz-drawer>\n\n<nz-modal\n [(nzVisible)]=\"isModalVisible\"\n nzTitle=\"Add template node\"\n [nzWidth]=\"600\"\n (nzOnCancel)=\"isModalVisible = false\"\n (nzOnOk)=\"addTemplateNodes()\"\n nzOkText=\"Add\"\n nzOkDanger\n nzCancelText=\"Cancel\"\n nzMaskClosable=\"false\"\n>\n <ng-container *nzModalContent>\n <extend-select\n label=\"Template\"\n [lstItem]=\"lstTemplateForSelect\"\n [displayField]=\"'Name'\"\n [multiple]=\"true\"\n [(_ngModel)]=\"lstTemplateSelected\"\n ></extend-select>\n </ng-container>\n</nz-modal>\n", styles: ["@charset \"UTF-8\";::ng-deep .workflow-wrapper{border:solid 1px lightgray;overflow:hidden;width:100%}.workflow-canvas{position:relative;background:#f0f2f5;cursor:default;overflow:hidden;outline:1px dashed rgba(0,0,0,.1)}.workflow-canvas .edges-layer{position:absolute;inset:0;width:100%;height:100%;z-index:1}.workflow-canvas .edges-layer path{stroke-width:2;fill:none}.canvas-content{transform-origin:0 0;width:100%;height:100%;transition:transform .05s linear}.canvas-content{outline:1px dashed red}.canvas-content.panning{cursor:grab}.canvas-content.panning:active{cursor:grabbing}.workflow-canvas.panning{cursor:grab}.workflow-canvas.panning:active{cursor:grabbing}.workflow-canvas.connecting,.workflow-canvas.connecting .workflow-node{cursor:crosshair}.workflow-node{position:absolute;width:160px;cursor:grab;-webkit-user-select:none;user-select:none;z-index:2}.workflow-node:active{cursor:grabbing}.workflow-node.connecting-source,.workflow-node.selected,.workflow-node:hover:not(.workflow-node-start,.workflow-node-end){outline:2px dashed #1890ff}.workflow-node .title{font-weight:600;margin-bottom:6px}.workflow-node-start{width:0px}.workflow-node-start.connecting-source,.workflow-node-start.selected,.workflow-node-start:hover{outline:unset}.workflow-node-start.connecting-source nz-tag,.workflow-node-start.selected nz-tag,.workflow-node-start:hover nz-tag{outline:2px dashed}.workflow-node-start nz-tag{position:relative;top:45px;right:35px}.workflow-node-end{width:0px}.workflow-node-end.connecting-source,.workflow-node-end.selected,.workflow-node-end:hover{outline:unset}.workflow-node-end.connecting-source nz-tag,.workflow-node-end.selected nz-tag,.workflow-node-end:hover nz-tag{outline:2px dashed}.workflow-node-end nz-tag{position:relative;top:45px;right:32px}.connector{position:absolute;top:39px;width:12px;height:12px;background:#1890ff;border-radius:50%;transform:translateY(-50%);cursor:crosshair;transition:box-shadow .15s ease-out,transform .15s ease-out}.connector:hover{box-shadow:0 0 0 3px #1890ff4d;transform:translateY(-50%) scale(1.15)}.connector-right{right:-8px;background:orange}.connector-right.reverse,.connector-left{left:-8px}.connector-left.reverse{left:unset;right:-8px}.connector-start{width:16px;height:16px;right:-8px;background:green;box-shadow:0 0 0 3px #1890ff4d}.connector-end{width:16px;height:16px;left:-8px;background:#000;box-shadow:0 0 0 3px #1890ff4d}.edge{cursor:pointer;stroke:#1890ff;stroke-linecap:round;stroke-linejoin:round;stroke-width:2;fill:none;transition:stroke .15s ease}.edge-hit{stroke:transparent;stroke-width:18px!important;fill:none;cursor:pointer}.edge-hit:hover+.edge{stroke:#ff4d4f;stroke-width:2}.workflow-canvas.dragging-point .edge-hit{pointer-events:none}.edge:hover+.edge-label{fill:#1890ff;font-weight:500}.edge-label{font-size:12px;fill:#555;pointer-events:none;-webkit-user-select:none;user-select:none}.blue{stroke:#1890ff!important}.red{stroke:#ff4d4f!important;box-shadow:0 0 0 3px #1890ff4d!important}.workflow-svg{background:transparent;overflow:visible}.waypoint{position:absolute;width:10px;height:10px;background:#ff4d4f;border-radius:50%;transform:translate(-50%,-50%) scale(1);cursor:move;z-index:1;transition:transform .12s ease-out,background-color .12s ease-out,box-shadow .12s ease-out}.waypoint:hover{background:#ff7875;transform:translate(-50%,-50%) scale(1.25);box-shadow:0 0 0 4px #ff787559}.waypoint.dragging{transition:none;transform:translate(-50%,-50%) scale(1.15);pointer-events:none}.workflow-canvas.dragging-point svg{cursor:grabbing}.selection-box{position:absolute;border:1px dashed #1890ff;background:#1890ff1a;pointer-events:none}.toolbar{position:absolute;top:8px;left:8px;display:flex;gap:4px;padding:6px;background:#fff;border-radius:6px;box-shadow:0 2px 8px #00000026;z-index:100}.toolbar .divider{width:1px;background:#e5e5e5;margin:0 2px}nz-tag.selected{outline:2px dashed #1890ff}.grid-layer{position:absolute;inset:0;pointer-events:none;z-index:0;background-image:radial-gradient(rgba(0,0,0,.08) 1px,transparent 1px);background-size:20px 20px}.grid-layer{background-image:linear-gradient(to right,rgba(0,0,0,.06) 1px,transparent 1px),linear-gradient(to bottom,rgba(0,0,0,.06) 1px,transparent 1px);background-size:20px 20px}.editable-tag{background:#fff;border-style:dashed}::ng-deep .minimap,.minimap-combine{position:absolute;width:180px;height:125px;top:0;right:0;background-color:#eee;border:1px solid #aaa;opacity:.9;z-index:1}::ng-deep .minimap{position:absolute;width:200px;height:140px;top:8px;right:8px;background-color:#f8f9fa;border:1px solid #d9d9d9;border-radius:8px;box-shadow:0 4px 12px #0000001a;overflow:hidden;z-index:100;-webkit-user-select:none;user-select:none}::ng-deep .minimap-node{position:absolute;background-color:#bfbfbf;border-radius:2px}::ng-deep .minimap-node-round{position:absolute;background-color:#bfbfbf;border-radius:50%}::ng-deep .minimap-node-round-start{background-color:#52c41a}::ng-deep .minimap-node-round-end{background-color:#ff4d4f}::ng-deep .minimap-viewport{position:absolute;box-sizing:border-box;background-color:#1890ff26;border:1.5px solid #1890ff;border-radius:4px;z-index:2;cursor:grab;transition:none}::ng-deep .minimap-viewport.grabbing,::ng-deep .minimap-viewport:active{cursor:grabbing;background-color:#1890ff40}::ng-deep .has-floating-label.floating-label{position:relative;padding-top:14px}::ng-deep .has-floating-label nz-form-item nz-form-label{position:absolute;top:12px;left:13px;transform:translateY(-50%);background:linear-gradient(to bottom,var(--form-bg-color, #ffffff) 80%,#ffffff 80%);z-index:1;height:auto;line-height:normal;padding:0 4px}::ng-deep .has-floating-label nz-form-item nz-form-label label{font-size:12px;color:var(--darkgray, #565656);font-weight:700;height:auto;line-height:normal;padding:0;display:flex;align-items:center}::ng-deep .has-floating-label .full-width{width:100%}.has-floating-label.floating-label nz-form-item:has(.ant-select-disabled) nz-form-label,.has-floating-label.floating-label nz-form-item:has(input[disabled]) nz-form-label,.has-floating-label.floating-label nz-form-item:has(.ant-input-disabled) nz-form-label{background:linear-gradient(to bottom,var(--form-bg-color, #ffffff) 60%,#f5f5f5 50%)}.has-floating-label.floating-label nz-form-item:has(.ant-select-disabled) nz-form-label label,.has-floating-label.floating-label nz-form-item:has(input[disabled]) nz-form-label label,.has-floating-label.floating-label nz-form-item:has(.ant-input-disabled) nz-form-label label{color:#bfbfbf}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: NzCardModule }, { kind: "component", type: i3$5.NzCardComponent, selector: "nz-card", inputs: ["nzBordered", "nzLoading", "nzHoverable", "nzBodyStyle", "nzCover", "nzActions", "nzType", "nzSize", "nzTitle", "nzExtra"], exportAs: ["nzCard"] }, { kind: "ngmodule", type: NzDrawerModule }, { kind: "component", type: i3$6.NzDrawerComponent, selector: "nz-drawer", inputs: ["nzContent", "nzCloseIcon", "nzClosable", "nzMaskClosable", "nzMask", "nzCloseOnNavigation", "nzNoAnimation", "nzKeyboard", "nzTitle", "nzExtra", "nzFooter", "nzPlacement", "nzSize", "nzMaskStyle", "nzBodyStyle", "nzWrapClassName", "nzWidth", "nzHeight", "nzZIndex", "nzOffsetX", "nzOffsetY", "nzVisible"], outputs: ["nzOnViewInit", "nzOnClose", "nzVisibleChange"], exportAs: ["nzDrawer"] }, { kind: "directive", type: i3$6.NzDrawerContentDirective, selector: "[nzDrawerContent]", exportAs: ["nzDrawerContent"] }, { kind: "ngmodule", type: NzTagModule }, { kind: "ngmodule", type: NzRadioModule }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1$2.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "component", type: Box, selector: "box", inputs: ["display", "width", "height"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i2$2.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i3$2.ɵNzTransitionPatchDirective, selector: "[nz-button], nz-button-group, [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i4$1.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }, { kind: "ngmodule", type: NzToolTipModule }, { kind: "directive", type: i8.NzTooltipDirective, selector: "[nz-tooltip]", inputs: ["nzTooltipTitle", "nzTooltipTitleContext", "nz-tooltip", "nzTooltipTrigger", "nzTooltipPlacement", "nzTooltipOrigin", "nzTooltipVisible", "nzTooltipMouseEnterDelay", "nzTooltipMouseLeaveDelay", "nzTooltipOverlayClassName", "nzTooltipOverlayStyle", "nzTooltipArrowPointAtCenter", "cdkConnectedOverlayPush", "nzTooltipColor"], outputs: ["nzTooltipVisibleChange"], exportAs: ["nzTooltip"] }, { kind: "component", type: ExtendInput, selector: "extend-input", inputs: ["label", "floatingLabel", "placeHolder", "labelAlign", "inputClass", "labelSpan", "labelFlex", "inputFlex", "showClear", "disabled", "readOnly", "required", "noBottom", "selectModeType", "autocomplete", "autofocus", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "size", "displayField", "valueField", "formData", "controlName", "_ngModel", "isSubmited"], outputs: ["_ngModelChange", "onclickClearIcon", "onenter"] }, { kind: "component", type: ExtendSelectComponent, selector: "extend-select", inputs: ["label", "floatingLabel", "placeHolder", "labelAlign", "dropdownMatchSelectWidth", "labelSpan", "labelFlex", "disabled", "required", "noBottom", "multiple", "showSelectAll", "maxTagCount", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "size", "lstItem", "displayField", "displayFields", "info", "valueField", "formData", "controlName", "_ngModel", "isSubmited"], outputs: ["_ngModelChange", "itemChange", "onFocus"] }, { kind: "component", type: ExtendCheckbox, selector: "extend-checkbox", inputs: ["label", "labelSpan", "labelFlex", "paddingTop", "disabled", "formData", "controlName", "valueType", "_ngModel"], outputs: ["_ngModelChange"] }, { kind: "component", type: ExtendTextArea, selector: "extend-textarea", inputs: ["label", "placeHolder", "labelAlign", "floatingLabel", "displayInline", "formItemNoButtom", "labelSpan", "labelFlex", "inputFlex", "disabled", "required", "noBottom", "selectModeType", "inputClass", "size", "isSubmited", "minRows", "maxRows", "lstItem", "displayField", "valueField", "formData", "controlName", "_ngModel", "isTouched", "inputErrorMessage", "errorMessages"], outputs: ["_ngModelChange"] }, { kind: "ngmodule", type: NzInputModule }, { kind: "ngmodule", type: NzGridModule }, { kind: "directive", type: i2$1.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "ngmodule", type: NzFlexModule }, { kind: "directive", type: i3$3.NzFlexDirective, selector: "[nz-flex],nz-flex", inputs: ["nzVertical", "nzJustify", "nzAlign", "nzGap", "nzWrap", "nzFlex"], exportAs: ["nzFlex"] }, { kind: "ngmodule", type: NzTableModule }, { kind: "ngmodule", type: NzDividerModule }, { kind: "ngmodule", type: NzAutocompleteModule }, { kind: "component", type: NzModalComponent, selector: "nz-modal", inputs: ["nzMask", "nzMaskClosable", "nzCloseOnNavigation", "nzVisible", "nzClosable", "nzOkLoading", "nzOkDisabled", "nzCancelDisabled", "nzCancelLoading", "nzKeyboard", "nzNoAnimation", "nzCentered", "nzDraggable", "nzContent", "nzFooter", "nzZIndex", "nzWidth", "nzWrapClassName", "nzClassName", "nzStyle", "nzTitle", "nzCloseIcon", "nzMaskStyle", "nzBodyStyle", "nzOkText", "nzCancelText", "nzOkType", "nzOkDanger", "nzIconType", "nzModalType", "nzAutofocus", "nzOnOk", "nzOnCancel"], outputs: ["nzOnOk", "nzOnCancel", "nzAfterOpen", "nzAfterClose", "nzVisibleChange"], exportAs: ["nzModal"] }, { kind: "directive", type: NzModalContentDirective, selector: "[nzModalContent]", exportAs: ["nzModalContent"] }, { kind: "component", type: WF_TemplateDetail, selector: "wf-template-detail" }] });
19442
19461
  }
19443
19462
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WF_Template_CombineEditorComponent, decorators: [{
19444
19463
  type: Component,
@@ -19474,7 +19493,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImpor
19474
19493
  DicDomainSelectComponent$1,
19475
19494
  IconInfo,
19476
19495
  WF_TemplateDetail,
19477
- ], selector: 'app-workflow-combine-editor', template: "<div\n #canvas\n class=\"workflow-canvas\"\n [class.connecting]=\"!!connectingFrom\"\n [class.dragging-point]=\"!!draggingPoint\"\n style=\"width: 100%; height: 100%\"\n (mousedown)=\"onMouseDownCanvas($event)\"\n (mousemove)=\"onMouseMoveCanvas($event)\"\n (mouseup)=\"onMouseUpCanvas($event)\"\n (click)=\"onClickCanvas($event)\"\n (wheel)=\"onWheelCanvas($event)\"\n>\n <!-- TOOLBAR -->\n <div class=\"toolbar\" (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\n <button nz-button nzSize=\"small\" nz-tooltip=\"Editor setting\" (click)=\"settingVisible = true\">\n <nz-icon nzType=\"setting\"></nz-icon>\n </button>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Infomation\" (click)=\"infoVisible = true\">\n <nz-icon nzType=\"info-circle\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Global Setting\" (click)=\"drawTemplateVisibel = true\">\n <nz-icon nzType=\"setting\"></nz-icon> G\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nzDanger [nzLoading]=\"!ready\" nz-tooltip=\"Save (Ctrl + S)\" (click)=\"save()\">\n <nz-icon nzType=\"save\"></nz-icon>\n </button>\n <button nz-button nzSize=\"small\" nz-tooltip=\"Th\u00EAm Template m\u1EDBi\" (click)=\"isModalVisible = true\">\n <nz-icon nzType=\"plus\" class=\"color-primary\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Move mode\"\n (click)=\"isMoveMode = true\"\n >\n <nz-icon><img src=\"/assets/icon/hand-palm.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"!isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Select mode\"\n (click)=\"isMoveMode = false\"\n >\n <nz-icon><img src=\"/assets/icon/cursor.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- UNDO / REDO -->\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"undoStack.length === 0\"\n nz-tooltip=\"Undo\"\n (click)=\"undo()\"\n >\n <nz-icon nzType=\"undo\"></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"redoStack.length === 0\"\n nz-tooltip=\"Redo\"\n (click)=\"redo()\"\n >\n <nz-icon nzType=\"redo\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ALIGN -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignLeft()\">\u27F8</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignCenter()\">\u2261</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignRight()\">\u27F9</button>\n <span class=\"divider\"></span>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignTop()\">\u21D1</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignMiddle()\">\u2550</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignBottom()\">\u21D3</button>\n <span class=\"divider\"></span>\n <!-- DISTRIBUTE -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 3\" (click)=\"distributeHorizontal()\">\n \u21C4\n </button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 3\" (click)=\"distributeVertical()\">\n \u21C5\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ZOOM -->\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"zoomOut()\" nz-tooltip=\"Zoom Out\">\n <nz-icon nzType=\"minus\"></nz-icon>\n </button>\n <span>{{ Math.round(zoom * 100) }}%</span>\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"zoomIn()\" nz-tooltip=\"Zoom In\">\n <nz-icon nzType=\"plus\"></nz-icon>\n </button>\n <span class=\"divider\"></span>\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"resetZoom()\" nz-tooltip=\"Reset Zoom (Ctrl+0)\">\n <nz-icon nzType=\"expand\"></nz-icon>\n </button>\n </div>\n\n <div\n class=\"canvas-content\"\n [class.panning]=\"isMoveMode\"\n [style.width.px]=\"getCanvasWidth()\"\n [style.height.px]=\"getCanvasHeight()\"\n [style.transform]=\"\n 'translate(' +\n templateCombine.editorOption.panX +\n 'px,' +\n templateCombine.editorOption.panY +\n 'px) scale(' +\n zoom +\n ')'\n \"\n >\n <!-- GRID -->\n <div *ngIf=\"wfcSetting.ShowGrid\" class=\"grid-layer\"></div>\n\n <!-- SVG EDGES -->\n <svg #svg class=\"edges-layer\" width=\"100%\" height=\"100%\" preserveAspectRatio=\"none\">\n <g>\n <!-- DEFS -->\n <defs>\n <filter id=\"edge-glow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n <feGaussianBlur stdDeviation=\"2\" result=\"blur\" />\n <feMerge>\n <feMergeNode in=\"blur\" />\n <feMergeNode in=\"SourceGraphic\" />\n </feMerge>\n </filter>\n\n <marker\n id=\"arrow-blue\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n <marker\n id=\"arrow-red\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n </defs>\n\n <!-- EDGES B\u00CCNH TH\u01AF\u1EDCNG -->\n <ng-container *ngFor=\"let e of normalEdges; let i = index\">\n <path class=\"edge\" [attr.id]=\"'edge-path-' + i\" [attr.d]=\"buildPath(e)\" marker-end=\"url(#arrow-blue)\"></path>\n\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseenter)=\"onMouseEnterEdge(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <!-- \u0110\u00E3 x\u00F3a *ngIf=\"e.RuleLineDetails?.length\" \u1EDF \u0111\u00E2y \u0111\u1EC3 text lu\u00F4n hi\u1EC7n -->\n <text\n class=\"edge-label\"\n style=\"fill: #1890ff; font-weight: 500\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.FromStage }} > {{ e.FromAction }}\n </text>\n </ng-container>\n\n <!-- EDGE \u0110ANG HOVER/SELECTED (HI\u1EC2N TH\u1ECA M\u00C0U \u0110\u1ECE) -->\n <ng-container *ngFor=\"let e of hoverEdges; let i = index\">\n <path\n class=\"edge red\"\n [attr.id]=\"'edge-path-hover-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-red)\"\n ></path>\n\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <text\n class=\"edge-label\"\n style=\"font-weight: bold; fill: red\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.FromStage }} > {{ e.FromAction }}\n </text>\n </ng-container>\n\n <!-- PREVIEW LINE (\u0110\u01AF\u1EDCNG N\u1ED0I \u0110ANG K\u00C9O) -->\n <path\n *ngIf=\"connectingFrom\"\n class=\"edge\"\n [attr.d]=\"buildPreviewPath()\"\n stroke-dasharray=\"5,5\"\n marker-end=\"url(#arrow-blue)\"\n ></path>\n </g>\n </svg>\n\n <!-- BOX V\u00D9NG CH\u1ECCN MULTI -->\n <div\n *ngIf=\"isSelecting && selectStart && selectEnd\"\n class=\"selection-box\"\n [style.left.px]=\"Math.min(selectStart.x, selectEnd.x)\"\n [style.top.px]=\"Math.min(selectStart.y, selectEnd.y)\"\n [style.width.px]=\"Math.abs(selectEnd.x - selectStart.x)\"\n [style.height.px]=\"Math.abs(selectEnd.y - selectStart.y)\"\n ></div>\n\n <!-- NODE (TEMPLATE) L\u1EDAP HI\u1EC2N TH\u1ECA TR\u00CAN C\u00D9NG -->\n @for (n of lstTemplateNode; track n.WF_Template_Id) {\n <nz-card\n class=\"workflow-node\"\n [attr.data-id]=\"n.Code\"\n [class.selected]=\"\n n == selectedTemplateNode || n == hoverTemplateNode || lstSelectedTemplateId.has(n.WF_Template_Id)\n \"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n) || isDraggingFrom(n) || isSelectedNode(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickNode(n)\"\n >\n <div class=\"title\" style=\"color: #1890ff; display: flex; justify-content: space-between; align-items: center\">\n <span>{{ n.Code }}</span>\n <nz-icon nzType=\"layout\" nzTheme=\"outline\"></nz-icon>\n </div>\n <div\n style=\"\n font-size: 12px;\n line-height: 1.2;\n font-weight: 500;\n height: 28px;\n overflow: hidden;\n text-overflow: ellipsis;\n \"\n >\n {{ n.Name || \"Ch\u01B0a c\u00F3 t\u00EAn\" }}\n </div>\n <div style=\"font-size: 10px; color: gray; margin-top: 4px\">\n {{ n.DocType }}\n </div>\n\n <!-- CONNECTOR \u0110\u1EC2 K\u00C9O D\u00C2Y -->\n <div class=\"connector connector-right\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n <div class=\"connector connector-left\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n </nz-card>\n }\n\n <!-- C\u00C1C \u0110I\u1EC2M WAYPOINT \u0110\u1EC2 B\u1EBA CONG D\u00C2Y CHU\u1ED8T -->\n @for (p of connectingPoints; track $index) {\n @if (p != draggingPoint) {\n <div\n class=\"waypoint\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n (contextmenu)=\"onRightClickPoint($event, hoverTemplateEdge!, $index)\"\n ></div>\n } @else {\n <div\n class=\"waypoint dragging\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n ></div>\n }\n }\n </div>\n</div>\n\n<!-- ==============================================\n 1. DRAWER: GLOBAL TEMPLATE SETTINGS \n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawTemplateTitle\"\n nzPlacement=\"right\"\n [nzWidth]=\"500\"\n [nzClosable]=\"false\"\n [nzVisible]=\"drawTemplateVisibel\"\n [nzFooter]=\"footerTplTemplate\"\n (nzOnClose)=\"drawTemplateVisibel = false\"\n>\n <ng-template #drawTemplateTitle> <nz-icon nzType=\"global\"></nz-icon> &nbsp; Quy tr\u00ECnh ph\u1ED1i h\u1EE3p </ng-template>\n <ng-container *nzDrawerContent>\n <!-- Gi\u1EEF nguy\u00EAn c\u00E1c th\u00F4ng tin chung to\u00E0n c\u1EE5c c\u1EE7a b\u1EA1n \u1EDF \u0111\u00E2y -->\n\n <extend-input [label]=\"'Code'\" [(_ngModel)]=\"templateCombine.Code\"></extend-input>\n <extend-input [label]=\"'Name'\" [(_ngModel)]=\"templateCombine.Name\"></extend-input>\n <extend-textarea [label]=\"'Description'\" [(_ngModel)]=\"templateCombine.Description\"></extend-textarea>\n <extend-checkbox [label]=\"'Active'\" [(_ngModel)]=\"templateCombine.IsActive\"></extend-checkbox>\n </ng-container>\n\n <ng-template #footerTplTemplate>\n <div nz-flex [nzGap]=\"6\" [nzJustify]=\"'end'\">\n <button nz-button nzDanger [nzLoading]=\"!ready\" (click)=\"save()\">Save</button>\n <button nz-button (click)=\"drawTemplateVisibel = false\">Close</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- ==============================================\n 2. DRAWER: NODE SETTINGS (CHI TI\u1EBET M\u1ED8T TEMPLATE)\n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawerTitleNode\"\n [nzPlacement]=\"selectedTemplateNode?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzVisible]=\"!!selectedTemplateNode\"\n [nzWidth]=\"'90vw'\"\n [nzClosable]=\"false\"\n [nzFooter]=\"footerTplNode\"\n (nzOnClose)=\"selectedTemplateNode = undefined\"\n>\n <ng-template #drawerTitleNode>\n <div nz-row nzJustify=\"space-between\">\n <span style=\"font-weight: bold; color: #1890ff\"\n ><nz-icon nzType=\"layout\"></nz-icon> TEMPLATE NODE: [{{ selectedTemplateNode?.Code }}]\n {{ selectedTemplateNode?.Name }}</span\n >\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"Chuy\u1EC3n v\u1ECB tr\u00ED Drawer\"\n (click)=\"\n selectedTemplateNode!.editorOption.drawerPosition =\n selectedTemplateNode!.editorOption.drawerPosition === 'left' ? 'right' : 'left'\n \"\n >\n <nz-icon nzType=\"swap\"></nz-icon>\n </button>\n </div>\n </ng-template>\n\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedTemplateNode\">\n <wf-template-detail #wftemplatedetail></wf-template-detail>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplNode>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedTemplateNode?.editorOption?.drawerPosition == 'left' ? 'start' : 'end'\"\n >\n <button nz-button nzDanger [nzLoading]=\"!ready\" (click)=\"wftemplatedetail.wfeditor.save()\">Save</button>\n <button nz-button (click)=\"selectedTemplateNode = undefined\">Close</button>\n <button nz-button nzDanger (click)=\"deleteTemplateNode()\">Delete Template node</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- ==============================================\n 3. DRAWER: EDGE SETTINGS (QU\u1EA2N L\u00DD QUY T\u1EAEC CHUY\u1EC2N TEMPLATE)\n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawerTitleEdge\"\n [nzPlacement]=\"selectedTemplateEdge?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzClosable]=\"false\"\n [nzWidth]=\"'450px'\"\n [nzVisible]=\"!!selectedTemplateEdge\"\n [nzFooter]=\"footerTplEdge\"\n (nzOnClose)=\"selectedTemplateEdge = undefined\"\n>\n <ng-template #drawerTitleEdge>\n <div nz-row nzJustify=\"space-between\">\n <span style=\"font-weight: bold; color: #ff4d4f\"><nz-icon nzType=\"swap-right\"></nz-icon> TRANSITION RULES </span>\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"Chuy\u1EC3n v\u1ECB tr\u00ED Drawer\"\n (click)=\"\n selectedTemplateEdge!.editorOption.drawerPosition =\n selectedTemplateEdge!.editorOption.drawerPosition === 'left' ? 'right' : 'left'\n \"\n >\n <nz-icon nzType=\"swap\"></nz-icon>\n </button>\n </div>\n </ng-template>\n\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedTemplateEdge\">\n <!-- Th\u00F4ng tin 2 \u0111\u1EA7u n\u1ED1i -->\n <div\n style=\"background: #fdf5f6; padding: 12px; border: 1px solid #ffa39e; border-radius: 6px; margin-bottom: 16px\"\n >\n <div style=\"font-size: 14px\">\n <strong style=\"display: inline-block; width: 70px; color: #555\">From:</strong>\n <span style=\"color: #1890ff; font-weight: 500\">\n [{{ getNode(selectedTemplateEdge.From_WF_Template_Id)?.Code }}]\n {{ getNode(selectedTemplateEdge.From_WF_Template_Id)?.Name }} > {{ selectedTemplateEdge.FromStage }} >\n {{ selectedTemplateEdge.FromAction }}\n </span>\n </div>\n <div style=\"font-size: 14px; margin-top: 8px\">\n <strong style=\"display: inline-block; width: 70px; color: #555\">Taget:</strong>\n <span style=\"color: #1890ff; font-weight: 500\">\n [{{ getNode(selectedTemplateEdge.To_WF_Template_Id)?.Code }}]\n {{ getNode(selectedTemplateEdge.To_WF_Template_Id)?.Name }} > {{ selectedTemplateEdge.ToStage }} >\n {{ selectedTemplateEdge.ToAction }}\n </span>\n </div>\n </div>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplEdge>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedTemplateEdge?.editorOption?.drawerPosition == 'left' ? 'start' : 'end'\"\n >\n <button nz-button nzDanger [nzLoading]=\"!ready\" (click)=\"save()\">Save Rules</button>\n <button\n nz-button\n nzDanger\n (click)=\"\n lstTemplateEdge.splice(lstTemplateEdge.indexOf(selectedTemplateEdge!), 1); selectedTemplateEdge = undefined\n \"\n >\n Delete Transition\n </button>\n <button nz-button (click)=\"selectedTemplateEdge = undefined\">Close</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- ==============================================\n 4. EDITOR SETTING & INFO\n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawSettingTitle\"\n nzPlacement=\"right\"\n [nzClosable]=\"false\"\n [nzVisible]=\"settingVisible\"\n (nzOnClose)=\"settingVisible = false\"\n>\n <ng-template #drawSettingTitle> <nz-icon nzType=\"setting\"></nz-icon> &nbsp; C\u00E0i \u0111\u1EB7t Editor </ng-template>\n <ng-container *nzDrawerContent>\n <div class=\"form-item-no-bottom\">\n <extend-checkbox\n [label]=\"'Hi\u1EC3n th\u1ECB L\u01B0\u1EDBi (Grid)'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"wfcSetting.ShowGrid\"\n ></extend-checkbox>\n </div>\n </ng-container>\n</nz-drawer>\n\n<nz-drawer\n [nzTitle]=\"drawInfoTitle\"\n nzPlacement=\"right\"\n [nzClosable]=\"false\"\n [nzVisible]=\"infoVisible\"\n (nzOnClose)=\"infoVisible = false\"\n>\n <ng-template #drawInfoTitle> <nz-icon nzType=\"info-circle\"></nz-icon> &nbsp; H\u01B0\u1EDBng d\u1EABn (Infomation) </ng-template>\n <ng-container *nzDrawerContent>\n <p>\n <strong>1. C\u00E1c th\u00E0nh ph\u1EA7n:</strong> C\u00E1c \u00F4 ch\u1EEF nh\u1EADt l\u00E0 Template (Quy tr\u00ECnh nh\u1ECF), c\u00E1c \u0111\u01B0\u1EDDng n\u1ED1i l\u00E0 Transition Rule\n (Quy t\u1EAFc chuy\u1EC3n quy tr\u00ECnh).\n </p>\n <p><strong>2. C\u00E1ch n\u1ED1i 2 Template:</strong></p>\n <ul>\n <li>Click ch\u1EA5m cam b\u00EAn ph\u1EA3i Template A, sau \u0111\u00F3 k\u00E9o v\u00E0 click v\u00E0o Template B \u0111\u1EC3 t\u1EA1o Rule n\u1ED1i.</li>\n <li>C\u00F3 th\u1EC3 click nhi\u1EC1u \u0111i\u1EC3m trong l\u00FAc k\u00E9o \u0111\u1EC3 b\u1EBB \u0111\u01B0\u1EDDng cong tu\u1EF3 \u00FD (Waypoint).</li>\n <li>Click \u0111\u00FAp v\u00E0o c\u1EA1nh (\u0111\u01B0\u1EDDng n\u1ED1i) \u0111ang c\u00F3 \u0111\u1EC3 t\u1EA1o th\u00EAm m\u1ED9t \u0111i\u1EC3m b\u1EBB cong m\u1EDBi.</li>\n <li>Gi\u1EEF v\u00E0 k\u00E9o \u0111i\u1EC3m b\u1EBB cong \u0111\u1EC3 tu\u1EF3 ch\u1EC9nh \u0111\u01B0\u1EDDng \u0111i. Chu\u1ED9t ph\u1EA3i v\u00E0o \u0111i\u1EC3m \u0111\u00F3 \u0111\u1EC3 x\u00F3a n\u00F3.</li>\n </ul>\n <p>\n <strong>3. Qu\u1EA3n l\u00FD Rule:</strong> Click v\u00E0o \u0111\u01B0\u1EDDng n\u1ED1i gi\u1EEFa 2 Node \u0111\u1EC3 c\u1EA5u h\u00ECnh c\u00E1c lu\u1ED3ng th\u1EF1c thi (Stored, Ph\u00E2n\n quy\u1EC1n, G\u1EEDi mail).\n </p>\n </ng-container>\n</nz-drawer>\n\n<nz-modal\n [(nzVisible)]=\"isModalVisible\"\n nzTitle=\"Add template node\"\n [nzWidth]=\"600\"\n (nzOnCancel)=\"isModalVisible = false\"\n (nzOnOk)=\"addTemplateNodes()\"\n nzOkText=\"Add\"\n nzOkDanger\n nzCancelText=\"Cancel\"\n nzMaskClosable=\"false\"\n>\n <ng-container *nzModalContent>\n <extend-select\n label=\"Template\"\n [lstItem]=\"lstTemplateForSelect\"\n [displayField]=\"'Name'\"\n [multiple]=\"true\"\n [(_ngModel)]=\"lstTemplateSelected\"\n ></extend-select>\n </ng-container>\n</nz-modal>\n", styles: ["@charset \"UTF-8\";::ng-deep .workflow-wrapper{border:solid 1px lightgray;overflow:hidden;width:100%}.workflow-canvas{position:relative;background:#f0f2f5;cursor:default;overflow:hidden;outline:1px dashed rgba(0,0,0,.1)}.workflow-canvas .edges-layer{position:absolute;inset:0;width:100%;height:100%;z-index:1}.workflow-canvas .edges-layer path{stroke-width:2;fill:none}.canvas-content{transform-origin:0 0;width:100%;height:100%;transition:transform .05s linear}.canvas-content{outline:1px dashed red}.canvas-content.panning{cursor:grab}.canvas-content.panning:active{cursor:grabbing}.workflow-canvas.panning{cursor:grab}.workflow-canvas.panning:active{cursor:grabbing}.workflow-canvas.connecting,.workflow-canvas.connecting .workflow-node{cursor:crosshair}.workflow-node{position:absolute;width:160px;cursor:grab;-webkit-user-select:none;user-select:none;z-index:2}.workflow-node:active{cursor:grabbing}.workflow-node.connecting-source,.workflow-node.selected,.workflow-node:hover:not(.workflow-node-start,.workflow-node-end){outline:2px dashed #1890ff}.workflow-node .title{font-weight:600;margin-bottom:6px}.workflow-node-start{width:0px}.workflow-node-start.connecting-source,.workflow-node-start.selected,.workflow-node-start:hover{outline:unset}.workflow-node-start.connecting-source nz-tag,.workflow-node-start.selected nz-tag,.workflow-node-start:hover nz-tag{outline:2px dashed}.workflow-node-start nz-tag{position:relative;top:45px;right:35px}.workflow-node-end{width:0px}.workflow-node-end.connecting-source,.workflow-node-end.selected,.workflow-node-end:hover{outline:unset}.workflow-node-end.connecting-source nz-tag,.workflow-node-end.selected nz-tag,.workflow-node-end:hover nz-tag{outline:2px dashed}.workflow-node-end nz-tag{position:relative;top:45px;right:32px}.connector{position:absolute;top:39px;width:12px;height:12px;background:#1890ff;border-radius:50%;transform:translateY(-50%);cursor:crosshair;transition:box-shadow .15s ease-out,transform .15s ease-out}.connector:hover{box-shadow:0 0 0 3px #1890ff4d;transform:translateY(-50%) scale(1.15)}.connector-right{right:-8px;background:orange}.connector-right.reverse,.connector-left{left:-8px}.connector-left.reverse{left:unset;right:-8px}.connector-start{width:16px;height:16px;right:-8px;background:green;box-shadow:0 0 0 3px #1890ff4d}.connector-end{width:16px;height:16px;left:-8px;background:#000;box-shadow:0 0 0 3px #1890ff4d}.edge{cursor:pointer;stroke:#1890ff;stroke-linecap:round;stroke-linejoin:round;stroke-width:2;fill:none;transition:stroke .15s ease}.edge-hit{stroke:transparent;stroke-width:18px!important;fill:none;cursor:pointer}.edge-hit:hover+.edge{stroke:#ff4d4f;stroke-width:2}.workflow-canvas.dragging-point .edge-hit{pointer-events:none}.edge:hover+.edge-label{fill:#1890ff;font-weight:500}.edge-label{font-size:12px;fill:#555;pointer-events:none;-webkit-user-select:none;user-select:none}.blue{stroke:#1890ff!important}.red{stroke:#ff4d4f!important;box-shadow:0 0 0 3px #1890ff4d!important}.workflow-svg{background:transparent;overflow:visible}.waypoint{position:absolute;width:10px;height:10px;background:#ff4d4f;border-radius:50%;transform:translate(-50%,-50%) scale(1);cursor:move;z-index:1;transition:transform .12s ease-out,background-color .12s ease-out,box-shadow .12s ease-out}.waypoint:hover{background:#ff7875;transform:translate(-50%,-50%) scale(1.25);box-shadow:0 0 0 4px #ff787559}.waypoint.dragging{transition:none;transform:translate(-50%,-50%) scale(1.15);pointer-events:none}.workflow-canvas.dragging-point svg{cursor:grabbing}.selection-box{position:absolute;border:1px dashed #1890ff;background:#1890ff1a;pointer-events:none}.toolbar{position:absolute;top:8px;left:8px;display:flex;gap:4px;padding:6px;background:#fff;border-radius:6px;box-shadow:0 2px 8px #00000026;z-index:100}.toolbar .divider{width:1px;background:#e5e5e5;margin:0 2px}nz-tag.selected{outline:2px dashed #1890ff}.grid-layer{position:absolute;inset:0;pointer-events:none;z-index:0;background-image:radial-gradient(rgba(0,0,0,.08) 1px,transparent 1px);background-size:20px 20px}.grid-layer{background-image:linear-gradient(to right,rgba(0,0,0,.06) 1px,transparent 1px),linear-gradient(to bottom,rgba(0,0,0,.06) 1px,transparent 1px);background-size:20px 20px}.editable-tag{background:#fff;border-style:dashed}::ng-deep .minimap,.minimap-combine{position:absolute;width:180px;height:125px;top:0;right:0;background-color:#eee;border:1px solid #aaa;opacity:.9;z-index:1}::ng-deep .minimap{position:absolute;width:200px;height:140px;top:8px;right:8px;background-color:#f8f9fa;border:1px solid #d9d9d9;border-radius:8px;box-shadow:0 4px 12px #0000001a;overflow:hidden;z-index:100;-webkit-user-select:none;user-select:none}::ng-deep .minimap-node{position:absolute;background-color:#bfbfbf;border-radius:2px}::ng-deep .minimap-node-round{position:absolute;background-color:#bfbfbf;border-radius:50%}::ng-deep .minimap-node-round-start{background-color:#52c41a}::ng-deep .minimap-node-round-end{background-color:#ff4d4f}::ng-deep .minimap-viewport{position:absolute;box-sizing:border-box;background-color:#1890ff26;border:1.5px solid #1890ff;border-radius:4px;z-index:2;cursor:grab;transition:none}::ng-deep .minimap-viewport.grabbing,::ng-deep .minimap-viewport:active{cursor:grabbing;background-color:#1890ff40}::ng-deep .has-floating-label.floating-label{position:relative;padding-top:14px}::ng-deep .has-floating-label nz-form-item nz-form-label{position:absolute;top:12px;left:13px;transform:translateY(-50%);background:linear-gradient(to bottom,var(--form-bg-color, #ffffff) 80%,#ffffff 80%);z-index:1;height:auto;line-height:normal;padding:0 4px}::ng-deep .has-floating-label nz-form-item nz-form-label label{font-size:12px;color:var(--darkgray, #565656);font-weight:700;height:auto;line-height:normal;padding:0;display:flex;align-items:center}::ng-deep .has-floating-label .full-width{width:100%}.has-floating-label.floating-label nz-form-item:has(.ant-select-disabled) nz-form-label,.has-floating-label.floating-label nz-form-item:has(input[disabled]) nz-form-label,.has-floating-label.floating-label nz-form-item:has(.ant-input-disabled) nz-form-label{background:linear-gradient(to bottom,var(--form-bg-color, #ffffff) 60%,#f5f5f5 50%)}.has-floating-label.floating-label nz-form-item:has(.ant-select-disabled) nz-form-label label,.has-floating-label.floating-label nz-form-item:has(input[disabled]) nz-form-label label,.has-floating-label.floating-label nz-form-item:has(.ant-input-disabled) nz-form-label label{color:#bfbfbf}\n"] }]
19496
+ ], selector: 'app-workflow-combine-editor', template: "<div\n #canvas\n class=\"workflow-canvas\"\n [class.connecting]=\"!!connectingFrom\"\n [class.dragging-point]=\"!!draggingPoint\"\n style=\"width: 100%; height: 100%\"\n (mousedown)=\"onMouseDownCanvas($event)\"\n (mousemove)=\"onMouseMoveCanvas($event)\"\n (mouseup)=\"onMouseUpCanvas($event)\"\n (click)=\"onClickCanvas($event)\"\n (wheel)=\"onWheelCanvas($event)\"\n>\n <!-- TOOLBAR -->\n <div class=\"toolbar\" (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\n <button nz-button nzSize=\"small\" nz-tooltip=\"Editor setting\" (click)=\"settingVisible = true\">\n <nz-icon nzType=\"setting\"></nz-icon>\n </button>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Infomation\" (click)=\"infoVisible = true\">\n <nz-icon nzType=\"info-circle\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Global Setting\" (click)=\"drawTemplateVisibel = true\">\n <nz-icon nzType=\"setting\"></nz-icon> G\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nzDanger [nzLoading]=\"!ready\" nz-tooltip=\"Save (Ctrl + S)\" (click)=\"save()\">\n <nz-icon nzType=\"save\"></nz-icon>\n </button>\n <button nz-button nzSize=\"small\" nz-tooltip=\"Th\u00EAm Template m\u1EDBi\" (click)=\"isModalVisible = true\">\n <nz-icon nzType=\"plus\" class=\"color-primary\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Move mode\"\n (click)=\"isMoveMode = true\"\n >\n <nz-icon><img src=\"/assets/icon/hand-palm.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"!isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Select mode\"\n (click)=\"isMoveMode = false\"\n >\n <nz-icon><img src=\"/assets/icon/cursor.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- UNDO / REDO -->\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"undoStack.length === 0\"\n nz-tooltip=\"Undo\"\n (click)=\"undo()\"\n >\n <nz-icon nzType=\"undo\"></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"redoStack.length === 0\"\n nz-tooltip=\"Redo\"\n (click)=\"redo()\"\n >\n <nz-icon nzType=\"redo\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ALIGN -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignLeft()\">\u27F8</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignCenter()\">\u2261</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignRight()\">\u27F9</button>\n <span class=\"divider\"></span>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignTop()\">\u21D1</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignMiddle()\">\u2550</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignBottom()\">\u21D3</button>\n <span class=\"divider\"></span>\n <!-- DISTRIBUTE -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 3\" (click)=\"distributeHorizontal()\">\n \u21C4\n </button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 3\" (click)=\"distributeVertical()\">\n \u21C5\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ZOOM -->\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"zoomOut()\" nz-tooltip=\"Zoom Out\">\n <nz-icon nzType=\"minus\"></nz-icon>\n </button>\n <span>{{ Math.round(zoom * 100) }}%</span>\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"zoomIn()\" nz-tooltip=\"Zoom In\">\n <nz-icon nzType=\"plus\"></nz-icon>\n </button>\n <span class=\"divider\"></span>\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"resetZoom()\" nz-tooltip=\"Reset Zoom (Ctrl+0)\">\n <nz-icon nzType=\"expand\"></nz-icon>\n </button>\n </div>\n\n <div\n class=\"canvas-content\"\n [class.panning]=\"isMoveMode\"\n [style.width.px]=\"getCanvasWidth()\"\n [style.height.px]=\"getCanvasHeight()\"\n [style.transform]=\"\n 'translate(' +\n templateCombine.editorOption.panX +\n 'px,' +\n templateCombine.editorOption.panY +\n 'px) scale(' +\n zoom +\n ')'\n \"\n >\n <!-- GRID -->\n <div *ngIf=\"wfcSetting.ShowGrid\" class=\"grid-layer\"></div>\n\n <!-- SVG EDGES -->\n <svg #svg class=\"edges-layer\" width=\"100%\" height=\"100%\" preserveAspectRatio=\"none\">\n <g>\n <!-- DEFS -->\n <defs>\n <filter id=\"edge-glow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n <feGaussianBlur stdDeviation=\"2\" result=\"blur\" />\n <feMerge>\n <feMergeNode in=\"blur\" />\n <feMergeNode in=\"SourceGraphic\" />\n </feMerge>\n </filter>\n\n <marker\n id=\"arrow-blue\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n <marker\n id=\"arrow-red\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n </defs>\n\n <!-- EDGES B\u00CCNH TH\u01AF\u1EDCNG -->\n <ng-container *ngFor=\"let e of normalEdges; let i = index\">\n <path class=\"edge\" [attr.id]=\"'edge-path-' + i\" [attr.d]=\"buildPath(e)\" marker-end=\"url(#arrow-blue)\"></path>\n\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseenter)=\"onMouseEnterEdge(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <!-- \u0110\u00E3 x\u00F3a *ngIf=\"e.RuleLineDetails?.length\" \u1EDF \u0111\u00E2y \u0111\u1EC3 text lu\u00F4n hi\u1EC7n -->\n <text\n class=\"edge-label\"\n style=\"fill: #1890ff; font-weight: 500\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.FromStage }} / {{ e.FromAction }} > {{ e.ToStage }} / {{ e.ToAction }}\n </text>\n </ng-container>\n\n <!-- EDGE \u0110ANG HOVER/SELECTED (HI\u1EC2N TH\u1ECA M\u00C0U \u0110\u1ECE) -->\n <ng-container *ngFor=\"let e of hoverEdges; let i = index\">\n <path\n class=\"edge red\"\n [attr.id]=\"'edge-path-hover-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-red)\"\n ></path>\n\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <text\n class=\"edge-label\"\n style=\"font-weight: bold; fill: red\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.FromStage }} / {{ e.FromAction }} > {{ e.ToStage }} / {{ e.ToAction }}\n </text>\n </ng-container>\n\n <!-- PREVIEW LINE (\u0110\u01AF\u1EDCNG N\u1ED0I \u0110ANG K\u00C9O) -->\n <path\n *ngIf=\"connectingFrom\"\n class=\"edge\"\n [attr.d]=\"buildPreviewPath()\"\n stroke-dasharray=\"5,5\"\n marker-end=\"url(#arrow-blue)\"\n ></path>\n </g>\n </svg>\n\n <!-- BOX V\u00D9NG CH\u1ECCN MULTI -->\n <div\n *ngIf=\"isSelecting && selectStart && selectEnd\"\n class=\"selection-box\"\n [style.left.px]=\"Math.min(selectStart.x, selectEnd.x)\"\n [style.top.px]=\"Math.min(selectStart.y, selectEnd.y)\"\n [style.width.px]=\"Math.abs(selectEnd.x - selectStart.x)\"\n [style.height.px]=\"Math.abs(selectEnd.y - selectStart.y)\"\n ></div>\n\n <!-- NODE (TEMPLATE) L\u1EDAP HI\u1EC2N TH\u1ECA TR\u00CAN C\u00D9NG -->\n @for (n of lstTemplateNode; track n.WF_Template_Id) {\n <nz-card\n class=\"workflow-node\"\n [attr.data-id]=\"n.Code\"\n [class.selected]=\"\n n == selectedTemplateNode || n == hoverTemplateNode || lstSelectedTemplateId.has(n.WF_Template_Id)\n \"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n) || isDraggingFrom(n) || isSelectedNode(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickNode(n)\"\n >\n <div class=\"title\" style=\"color: #1890ff; display: flex; justify-content: space-between; align-items: center\">\n <span>{{ n.Code }}</span>\n <nz-icon nzType=\"layout\" nzTheme=\"outline\"></nz-icon>\n </div>\n <div\n style=\"\n font-size: 12px;\n line-height: 1.2;\n font-weight: 500;\n height: 28px;\n overflow: hidden;\n text-overflow: ellipsis;\n \"\n >\n {{ n.Name || \"Ch\u01B0a c\u00F3 t\u00EAn\" }}\n </div>\n <div style=\"font-size: 10px; color: gray; margin-top: 4px\">\n {{ n.DocType }}\n </div>\n\n <!-- CONNECTOR \u0110\u1EC2 K\u00C9O D\u00C2Y -->\n <div class=\"connector connector-right\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n <div class=\"connector connector-left\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n </nz-card>\n }\n\n <!-- C\u00C1C \u0110I\u1EC2M WAYPOINT \u0110\u1EC2 B\u1EBA CONG D\u00C2Y CHU\u1ED8T -->\n @for (p of connectingPoints; track $index) {\n @if (p != draggingPoint) {\n <div\n class=\"waypoint\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n (contextmenu)=\"onRightClickPoint($event, hoverTemplateEdge!, $index)\"\n ></div>\n } @else {\n <div\n class=\"waypoint dragging\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n ></div>\n }\n }\n </div>\n</div>\n\n<!-- ==============================================\n 1. DRAWER: GLOBAL TEMPLATE SETTINGS \n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawTemplateTitle\"\n nzPlacement=\"right\"\n [nzWidth]=\"500\"\n [nzClosable]=\"false\"\n [nzVisible]=\"drawTemplateVisibel\"\n [nzFooter]=\"footerTplTemplate\"\n (nzOnClose)=\"drawTemplateVisibel = false\"\n>\n <ng-template #drawTemplateTitle> <nz-icon nzType=\"global\"></nz-icon> &nbsp; Quy tr\u00ECnh ph\u1ED1i h\u1EE3p </ng-template>\n <ng-container *nzDrawerContent>\n <!-- Gi\u1EEF nguy\u00EAn c\u00E1c th\u00F4ng tin chung to\u00E0n c\u1EE5c c\u1EE7a b\u1EA1n \u1EDF \u0111\u00E2y -->\n\n <extend-input [label]=\"'Code'\" [(_ngModel)]=\"templateCombine.Code\"></extend-input>\n <extend-input [label]=\"'Name'\" [(_ngModel)]=\"templateCombine.Name\"></extend-input>\n <extend-textarea [label]=\"'Description'\" [(_ngModel)]=\"templateCombine.Description\"></extend-textarea>\n <extend-checkbox [label]=\"'Active'\" [(_ngModel)]=\"templateCombine.IsActive\"></extend-checkbox>\n </ng-container>\n\n <ng-template #footerTplTemplate>\n <div nz-flex [nzGap]=\"6\" [nzJustify]=\"'end'\">\n <button nz-button nzDanger [nzLoading]=\"!ready\" (click)=\"save()\">Save</button>\n <button nz-button (click)=\"drawTemplateVisibel = false\">Close</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- ==============================================\n 2. DRAWER: NODE SETTINGS (CHI TI\u1EBET M\u1ED8T TEMPLATE)\n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawerTitleNode\"\n [nzPlacement]=\"selectedTemplateNode?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzVisible]=\"!!selectedTemplateNode\"\n [nzWidth]=\"'90vw'\"\n [nzClosable]=\"false\"\n [nzFooter]=\"footerTplNode\"\n (nzOnClose)=\"selectedTemplateNode = undefined\"\n>\n <ng-template #drawerTitleNode>\n <div nz-row nzJustify=\"space-between\">\n <span style=\"font-weight: bold; color: #1890ff\"\n ><nz-icon nzType=\"layout\"></nz-icon> TEMPLATE NODE: [{{ selectedTemplateNode?.Code }}]\n {{ selectedTemplateNode?.Name }}</span\n >\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"Chuy\u1EC3n v\u1ECB tr\u00ED Drawer\"\n (click)=\"\n selectedTemplateNode!.editorOption.drawerPosition =\n selectedTemplateNode!.editorOption.drawerPosition === 'left' ? 'right' : 'left'\n \"\n >\n <nz-icon nzType=\"swap\"></nz-icon>\n </button>\n </div>\n </ng-template>\n\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedTemplateNode\">\n <wf-template-detail #wftemplatedetail></wf-template-detail>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplNode>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedTemplateNode?.editorOption?.drawerPosition == 'left' ? 'start' : 'end'\"\n >\n <button nz-button nzDanger [nzLoading]=\"!ready\" (click)=\"wftemplatedetail.wfeditor.save()\">Save</button>\n <button nz-button (click)=\"selectedTemplateNode = undefined\">Close</button>\n <button nz-button nzDanger (click)=\"deleteTemplateNode()\">Delete Template node</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- ==============================================\n 3. DRAWER: EDGE SETTINGS (QU\u1EA2N L\u00DD QUY T\u1EAEC CHUY\u1EC2N TEMPLATE)\n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawerTitleEdge\"\n [nzPlacement]=\"selectedTemplateEdge?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzClosable]=\"false\"\n [nzWidth]=\"'450px'\"\n [nzVisible]=\"!!selectedTemplateEdge\"\n [nzFooter]=\"footerTplEdge\"\n (nzOnClose)=\"selectedTemplateEdge = undefined\"\n>\n <ng-template #drawerTitleEdge>\n <div nz-row nzJustify=\"space-between\">\n <span style=\"font-weight: bold; color: #ff4d4f\"><nz-icon nzType=\"swap-right\"></nz-icon> TRANSITION RULES </span>\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"Chuy\u1EC3n v\u1ECB tr\u00ED Drawer\"\n (click)=\"\n selectedTemplateEdge!.editorOption.drawerPosition =\n selectedTemplateEdge!.editorOption.drawerPosition === 'left' ? 'right' : 'left'\n \"\n >\n <nz-icon nzType=\"swap\"></nz-icon>\n </button>\n </div>\n </ng-template>\n\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedTemplateEdge\">\n <!-- Th\u00F4ng tin 2 \u0111\u1EA7u n\u1ED1i -->\n <div\n style=\"background: #fdf5f6; padding: 12px; border: 1px solid #ffa39e; border-radius: 6px; margin-bottom: 16px\"\n >\n <div style=\"font-size: 14px\">\n <strong style=\"display: inline-block; width: 70px; color: #555\">From:</strong>\n <span style=\"color: #1890ff; font-weight: 500\">\n [{{ getNode(selectedTemplateEdge.From_WF_Template_Id)?.Code }}]\n {{ getNode(selectedTemplateEdge.From_WF_Template_Id)?.Name }} > {{ selectedTemplateEdge.FromStage }} >\n {{ selectedTemplateEdge.FromAction }}\n </span>\n </div>\n <div style=\"font-size: 14px; margin-top: 8px\">\n <strong style=\"display: inline-block; width: 70px; color: #555\">Taget:</strong>\n <span style=\"color: #1890ff; font-weight: 500\">\n [{{ getNode(selectedTemplateEdge.To_WF_Template_Id)?.Code }}]\n {{ getNode(selectedTemplateEdge.To_WF_Template_Id)?.Name }} > {{ selectedTemplateEdge.ToStage }} >\n {{ selectedTemplateEdge.ToAction }}\n </span>\n </div>\n </div>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplEdge>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedTemplateEdge?.editorOption?.drawerPosition == 'left' ? 'start' : 'end'\"\n >\n <button nz-button nzDanger [nzLoading]=\"!ready\" (click)=\"save()\">Save Rules</button>\n <button\n nz-button\n nzDanger\n (click)=\"\n lstTemplateEdge.splice(lstTemplateEdge.indexOf(selectedTemplateEdge!), 1); selectedTemplateEdge = undefined\n \"\n >\n Delete Transition\n </button>\n <button nz-button (click)=\"selectedTemplateEdge = undefined\">Close</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- ==============================================\n 4. EDITOR SETTING & INFO\n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawSettingTitle\"\n nzPlacement=\"right\"\n [nzClosable]=\"false\"\n [nzVisible]=\"settingVisible\"\n (nzOnClose)=\"settingVisible = false\"\n>\n <ng-template #drawSettingTitle> <nz-icon nzType=\"setting\"></nz-icon> &nbsp; C\u00E0i \u0111\u1EB7t Editor </ng-template>\n <ng-container *nzDrawerContent>\n <div class=\"form-item-no-bottom\">\n <extend-checkbox\n [label]=\"'Hi\u1EC3n th\u1ECB L\u01B0\u1EDBi (Grid)'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"wfcSetting.ShowGrid\"\n ></extend-checkbox>\n </div>\n </ng-container>\n</nz-drawer>\n\n<nz-drawer\n [nzTitle]=\"drawInfoTitle\"\n nzPlacement=\"right\"\n [nzClosable]=\"false\"\n [nzVisible]=\"infoVisible\"\n (nzOnClose)=\"infoVisible = false\"\n>\n <ng-template #drawInfoTitle> <nz-icon nzType=\"info-circle\"></nz-icon> &nbsp; H\u01B0\u1EDBng d\u1EABn (Infomation) </ng-template>\n <ng-container *nzDrawerContent>\n <p>\n <strong>1. C\u00E1c th\u00E0nh ph\u1EA7n:</strong> C\u00E1c \u00F4 ch\u1EEF nh\u1EADt l\u00E0 Template (Quy tr\u00ECnh nh\u1ECF), c\u00E1c \u0111\u01B0\u1EDDng n\u1ED1i l\u00E0 Transition Rule\n (Quy t\u1EAFc chuy\u1EC3n quy tr\u00ECnh).\n </p>\n <p><strong>2. C\u00E1ch n\u1ED1i 2 Template:</strong></p>\n <ul>\n <li>Click ch\u1EA5m cam b\u00EAn ph\u1EA3i Template A, sau \u0111\u00F3 k\u00E9o v\u00E0 click v\u00E0o Template B \u0111\u1EC3 t\u1EA1o Rule n\u1ED1i.</li>\n <li>C\u00F3 th\u1EC3 click nhi\u1EC1u \u0111i\u1EC3m trong l\u00FAc k\u00E9o \u0111\u1EC3 b\u1EBB \u0111\u01B0\u1EDDng cong tu\u1EF3 \u00FD (Waypoint).</li>\n <li>Click \u0111\u00FAp v\u00E0o c\u1EA1nh (\u0111\u01B0\u1EDDng n\u1ED1i) \u0111ang c\u00F3 \u0111\u1EC3 t\u1EA1o th\u00EAm m\u1ED9t \u0111i\u1EC3m b\u1EBB cong m\u1EDBi.</li>\n <li>Gi\u1EEF v\u00E0 k\u00E9o \u0111i\u1EC3m b\u1EBB cong \u0111\u1EC3 tu\u1EF3 ch\u1EC9nh \u0111\u01B0\u1EDDng \u0111i. Chu\u1ED9t ph\u1EA3i v\u00E0o \u0111i\u1EC3m \u0111\u00F3 \u0111\u1EC3 x\u00F3a n\u00F3.</li>\n </ul>\n <p>\n <strong>3. Qu\u1EA3n l\u00FD Rule:</strong> Click v\u00E0o \u0111\u01B0\u1EDDng n\u1ED1i gi\u1EEFa 2 Node \u0111\u1EC3 c\u1EA5u h\u00ECnh c\u00E1c lu\u1ED3ng th\u1EF1c thi (Stored, Ph\u00E2n\n quy\u1EC1n, G\u1EEDi mail).\n </p>\n </ng-container>\n</nz-drawer>\n\n<nz-modal\n [(nzVisible)]=\"isModalVisible\"\n nzTitle=\"Add template node\"\n [nzWidth]=\"600\"\n (nzOnCancel)=\"isModalVisible = false\"\n (nzOnOk)=\"addTemplateNodes()\"\n nzOkText=\"Add\"\n nzOkDanger\n nzCancelText=\"Cancel\"\n nzMaskClosable=\"false\"\n>\n <ng-container *nzModalContent>\n <extend-select\n label=\"Template\"\n [lstItem]=\"lstTemplateForSelect\"\n [displayField]=\"'Name'\"\n [multiple]=\"true\"\n [(_ngModel)]=\"lstTemplateSelected\"\n ></extend-select>\n </ng-container>\n</nz-modal>\n", styles: ["@charset \"UTF-8\";::ng-deep .workflow-wrapper{border:solid 1px lightgray;overflow:hidden;width:100%}.workflow-canvas{position:relative;background:#f0f2f5;cursor:default;overflow:hidden;outline:1px dashed rgba(0,0,0,.1)}.workflow-canvas .edges-layer{position:absolute;inset:0;width:100%;height:100%;z-index:1}.workflow-canvas .edges-layer path{stroke-width:2;fill:none}.canvas-content{transform-origin:0 0;width:100%;height:100%;transition:transform .05s linear}.canvas-content{outline:1px dashed red}.canvas-content.panning{cursor:grab}.canvas-content.panning:active{cursor:grabbing}.workflow-canvas.panning{cursor:grab}.workflow-canvas.panning:active{cursor:grabbing}.workflow-canvas.connecting,.workflow-canvas.connecting .workflow-node{cursor:crosshair}.workflow-node{position:absolute;width:160px;cursor:grab;-webkit-user-select:none;user-select:none;z-index:2}.workflow-node:active{cursor:grabbing}.workflow-node.connecting-source,.workflow-node.selected,.workflow-node:hover:not(.workflow-node-start,.workflow-node-end){outline:2px dashed #1890ff}.workflow-node .title{font-weight:600;margin-bottom:6px}.workflow-node-start{width:0px}.workflow-node-start.connecting-source,.workflow-node-start.selected,.workflow-node-start:hover{outline:unset}.workflow-node-start.connecting-source nz-tag,.workflow-node-start.selected nz-tag,.workflow-node-start:hover nz-tag{outline:2px dashed}.workflow-node-start nz-tag{position:relative;top:45px;right:35px}.workflow-node-end{width:0px}.workflow-node-end.connecting-source,.workflow-node-end.selected,.workflow-node-end:hover{outline:unset}.workflow-node-end.connecting-source nz-tag,.workflow-node-end.selected nz-tag,.workflow-node-end:hover nz-tag{outline:2px dashed}.workflow-node-end nz-tag{position:relative;top:45px;right:32px}.connector{position:absolute;top:39px;width:12px;height:12px;background:#1890ff;border-radius:50%;transform:translateY(-50%);cursor:crosshair;transition:box-shadow .15s ease-out,transform .15s ease-out}.connector:hover{box-shadow:0 0 0 3px #1890ff4d;transform:translateY(-50%) scale(1.15)}.connector-right{right:-8px;background:orange}.connector-right.reverse,.connector-left{left:-8px}.connector-left.reverse{left:unset;right:-8px}.connector-start{width:16px;height:16px;right:-8px;background:green;box-shadow:0 0 0 3px #1890ff4d}.connector-end{width:16px;height:16px;left:-8px;background:#000;box-shadow:0 0 0 3px #1890ff4d}.edge{cursor:pointer;stroke:#1890ff;stroke-linecap:round;stroke-linejoin:round;stroke-width:2;fill:none;transition:stroke .15s ease}.edge-hit{stroke:transparent;stroke-width:18px!important;fill:none;cursor:pointer}.edge-hit:hover+.edge{stroke:#ff4d4f;stroke-width:2}.workflow-canvas.dragging-point .edge-hit{pointer-events:none}.edge:hover+.edge-label{fill:#1890ff;font-weight:500}.edge-label{font-size:12px;fill:#555;pointer-events:none;-webkit-user-select:none;user-select:none}.blue{stroke:#1890ff!important}.red{stroke:#ff4d4f!important;box-shadow:0 0 0 3px #1890ff4d!important}.workflow-svg{background:transparent;overflow:visible}.waypoint{position:absolute;width:10px;height:10px;background:#ff4d4f;border-radius:50%;transform:translate(-50%,-50%) scale(1);cursor:move;z-index:1;transition:transform .12s ease-out,background-color .12s ease-out,box-shadow .12s ease-out}.waypoint:hover{background:#ff7875;transform:translate(-50%,-50%) scale(1.25);box-shadow:0 0 0 4px #ff787559}.waypoint.dragging{transition:none;transform:translate(-50%,-50%) scale(1.15);pointer-events:none}.workflow-canvas.dragging-point svg{cursor:grabbing}.selection-box{position:absolute;border:1px dashed #1890ff;background:#1890ff1a;pointer-events:none}.toolbar{position:absolute;top:8px;left:8px;display:flex;gap:4px;padding:6px;background:#fff;border-radius:6px;box-shadow:0 2px 8px #00000026;z-index:100}.toolbar .divider{width:1px;background:#e5e5e5;margin:0 2px}nz-tag.selected{outline:2px dashed #1890ff}.grid-layer{position:absolute;inset:0;pointer-events:none;z-index:0;background-image:radial-gradient(rgba(0,0,0,.08) 1px,transparent 1px);background-size:20px 20px}.grid-layer{background-image:linear-gradient(to right,rgba(0,0,0,.06) 1px,transparent 1px),linear-gradient(to bottom,rgba(0,0,0,.06) 1px,transparent 1px);background-size:20px 20px}.editable-tag{background:#fff;border-style:dashed}::ng-deep .minimap,.minimap-combine{position:absolute;width:180px;height:125px;top:0;right:0;background-color:#eee;border:1px solid #aaa;opacity:.9;z-index:1}::ng-deep .minimap{position:absolute;width:200px;height:140px;top:8px;right:8px;background-color:#f8f9fa;border:1px solid #d9d9d9;border-radius:8px;box-shadow:0 4px 12px #0000001a;overflow:hidden;z-index:100;-webkit-user-select:none;user-select:none}::ng-deep .minimap-node{position:absolute;background-color:#bfbfbf;border-radius:2px}::ng-deep .minimap-node-round{position:absolute;background-color:#bfbfbf;border-radius:50%}::ng-deep .minimap-node-round-start{background-color:#52c41a}::ng-deep .minimap-node-round-end{background-color:#ff4d4f}::ng-deep .minimap-viewport{position:absolute;box-sizing:border-box;background-color:#1890ff26;border:1.5px solid #1890ff;border-radius:4px;z-index:2;cursor:grab;transition:none}::ng-deep .minimap-viewport.grabbing,::ng-deep .minimap-viewport:active{cursor:grabbing;background-color:#1890ff40}::ng-deep .has-floating-label.floating-label{position:relative;padding-top:14px}::ng-deep .has-floating-label nz-form-item nz-form-label{position:absolute;top:12px;left:13px;transform:translateY(-50%);background:linear-gradient(to bottom,var(--form-bg-color, #ffffff) 80%,#ffffff 80%);z-index:1;height:auto;line-height:normal;padding:0 4px}::ng-deep .has-floating-label nz-form-item nz-form-label label{font-size:12px;color:var(--darkgray, #565656);font-weight:700;height:auto;line-height:normal;padding:0;display:flex;align-items:center}::ng-deep .has-floating-label .full-width{width:100%}.has-floating-label.floating-label nz-form-item:has(.ant-select-disabled) nz-form-label,.has-floating-label.floating-label nz-form-item:has(input[disabled]) nz-form-label,.has-floating-label.floating-label nz-form-item:has(.ant-input-disabled) nz-form-label{background:linear-gradient(to bottom,var(--form-bg-color, #ffffff) 60%,#f5f5f5 50%)}.has-floating-label.floating-label nz-form-item:has(.ant-select-disabled) nz-form-label label,.has-floating-label.floating-label nz-form-item:has(input[disabled]) nz-form-label label,.has-floating-label.floating-label nz-form-item:has(.ant-input-disabled) nz-form-label label{color:#bfbfbf}\n"] }]
19478
19497
  }], propDecorators: { lstTemplateForSelect: [{
19479
19498
  type: Input
19480
19499
  }], onSave: [{