@brggroup/share-lib 0.1.74 → 0.1.75

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.
@@ -11377,8 +11377,8 @@ let WorkflowEditorOption$1 = class WorkflowEditorOption {
11377
11377
  AllowbackInUse;
11378
11378
  constructor(obj) {
11379
11379
  obj = obj || {};
11380
- this.panX = obj.panX || 0;
11381
- this.panY = obj.panY || 0;
11380
+ this.panX = Math.round(obj.panX) || 0;
11381
+ this.panY = Math.round(obj.panY) || 0;
11382
11382
  this.AllowbackInUse = obj.AllowbackInUse || false;
11383
11383
  }
11384
11384
  };
@@ -11791,8 +11791,8 @@ class WorkflowEditorComponent extends BaseComponent {
11791
11791
  canvasHeight: this.getCanvasHeight(),
11792
11792
  nodes: this.lstStage, // Truyền trực tiếp mảng dữ liệu Node
11793
11793
  onPanChange: (x, y) => {
11794
- this.template.editorOption.panX = x;
11795
- this.template.editorOption.panY = y;
11794
+ this.template.editorOption.panX = Math.round(x);
11795
+ this.template.editorOption.panY = Math.round(y);
11796
11796
  },
11797
11797
  });
11798
11798
  }
@@ -12747,8 +12747,8 @@ class WorkflowEditorComponent extends BaseComponent {
12747
12747
  const canvasY = (y - this.template.editorOption.panY) / this.zoom;
12748
12748
  this.zoom = parseFloat(newZoom.toFixed(2));
12749
12749
  // Tính toán lại vị trí Pan để điểm đang trỏ vẫn nằm dưới chuột
12750
- this.template.editorOption.panX = x - canvasX * this.zoom;
12751
- this.template.editorOption.panY = y - canvasY * this.zoom;
12750
+ this.template.editorOption.panX = Math.round(x - canvasX * this.zoom);
12751
+ this.template.editorOption.panY = Math.round(y - canvasY * this.zoom);
12752
12752
  this.syncMiniMapViewport();
12753
12753
  }
12754
12754
  //#endregion
@@ -18145,6 +18145,7 @@ class WF_TemplateDetail extends BaseComponent {
18145
18145
  lstAction = [];
18146
18146
  lstActionRef = [];
18147
18147
  wfeditor;
18148
+ onSave = new EventEmitter();
18148
18149
  ngOnInit() {
18149
18150
  this.getMasterData();
18150
18151
  }
@@ -18214,6 +18215,7 @@ class WF_TemplateDetail extends BaseComponent {
18214
18215
  .then((res) => {
18215
18216
  this.notiService.success();
18216
18217
  this.getData(res.Data);
18218
+ this.onSave.emit();
18217
18219
  }, (err) => {
18218
18220
  this.handleError(err);
18219
18221
  this.wfeditor.ready = true;
@@ -18279,7 +18281,7 @@ class WF_TemplateDetail extends BaseComponent {
18279
18281
  this.wfeditor.actionRuleModalVisible = false;
18280
18282
  }
18281
18283
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WF_TemplateDetail, deps: null, target: i0.ɵɵFactoryTarget.Component });
18282
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.7", type: WF_TemplateDetail, isStandalone: true, selector: "wf-template-detail", viewQueries: [{ propertyName: "wfeditor", first: true, predicate: ["wfeditor"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"workflow-wrapper\" style=\"height: calc(100vh - 160px)\">\n <app-workflow-editor\n #wfeditor\n [lstOrg]=\"lstOrg\"\n [lstRole]=\"lstRole\"\n [lstUser]=\"lstUser\"\n [lstEmailTemplate]=\"lstEmailTemplate\"\n (onSave)=\"save($event)\"\n (onDeleteStage)=\"deleteStage($event)\"\n (onDeleteAction)=\"deleteAction($event)\"\n (onDeleteRule)=\"deleteRule($event)\"\n (onDeleteRuleLine)=\"deleteRuleLine($event)\"\n (onCheckRule)=\"onCheckRule($event)\"\n (onCheckAllRule)=\"onCheckAllRule($event)\"\n ></app-workflow-editor>\n</div>\n", styles: [".workflow-wrapper{position:relative}\n"], dependencies: [{ kind: "component", type: WorkflowEditorComponent, selector: "app-workflow-editor", inputs: ["lstOrg", "lstRole", "lstUser", "lstEmailTemplate"], outputs: ["onSave", "onDeleteStage", "onDeleteAction", "onDeleteRule", "onDeleteRuleLine", "onCheckRule", "onCheckAllRule"] }] });
18284
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.7", type: WF_TemplateDetail, isStandalone: true, selector: "wf-template-detail", outputs: { onSave: "onSave" }, viewQueries: [{ propertyName: "wfeditor", first: true, predicate: ["wfeditor"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"workflow-wrapper\" style=\"height: calc(100vh - 160px)\">\n <app-workflow-editor\n #wfeditor\n [lstOrg]=\"lstOrg\"\n [lstRole]=\"lstRole\"\n [lstUser]=\"lstUser\"\n [lstEmailTemplate]=\"lstEmailTemplate\"\n (onSave)=\"save($event)\"\n (onDeleteStage)=\"deleteStage($event)\"\n (onDeleteAction)=\"deleteAction($event)\"\n (onDeleteRule)=\"deleteRule($event)\"\n (onDeleteRuleLine)=\"deleteRuleLine($event)\"\n (onCheckRule)=\"onCheckRule($event)\"\n (onCheckAllRule)=\"onCheckAllRule($event)\"\n ></app-workflow-editor>\n</div>\n", styles: [".workflow-wrapper{position:relative}\n"], dependencies: [{ kind: "component", type: WorkflowEditorComponent, selector: "app-workflow-editor", inputs: ["lstOrg", "lstRole", "lstUser", "lstEmailTemplate"], outputs: ["onSave", "onDeleteStage", "onDeleteAction", "onDeleteRule", "onDeleteRuleLine", "onCheckRule", "onCheckAllRule"] }] });
18283
18285
  }
18284
18286
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WF_TemplateDetail, decorators: [{
18285
18287
  type: Component,
@@ -18287,6 +18289,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImpor
18287
18289
  }], propDecorators: { wfeditor: [{
18288
18290
  type: ViewChild,
18289
18291
  args: ['wfeditor']
18292
+ }], onSave: [{
18293
+ type: Output
18290
18294
  }] } });
18291
18295
 
18292
18296
  //#region MODELS
@@ -18372,8 +18376,8 @@ class WorkflowEditorOption {
18372
18376
  AllowbackInUse;
18373
18377
  constructor(obj) {
18374
18378
  obj = obj || {};
18375
- this.panX = obj.panX || 0;
18376
- this.panY = obj.panY || 0;
18379
+ this.panX = Math.round(obj.panX) || 0;
18380
+ this.panY = Math.round(obj.panY) || 0;
18377
18381
  this.AllowbackInUse = obj.AllowbackInUse || false;
18378
18382
  }
18379
18383
  }
@@ -18470,6 +18474,7 @@ class WorkflowTemplateEdge {
18470
18474
  //#endregion MODELS
18471
18475
  class WF_Template_CombineEditorComponent extends BaseComponent {
18472
18476
  lstTemplateForSelect = [];
18477
+ getdata = new EventEmitter();
18473
18478
  onSave = new EventEmitter();
18474
18479
  onDeleteTempldateNode = new EventEmitter();
18475
18480
  lstTemplateSelected = [];
@@ -18531,13 +18536,16 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
18531
18536
  svgRef;
18532
18537
  wftemplatedetail;
18533
18538
  get normalEdges() {
18534
- return this.lstTemplateEdge.filter((e) => e !== this.hoverTemplateEdge);
18539
+ const hoveredSet = new Set(this.hoverEdges);
18540
+ return this.lstTemplateEdge.filter((e) => !hoveredSet.has(e));
18535
18541
  }
18536
18542
  get hoverEdges() {
18537
- if (this.hoverTemplateEdge)
18538
- return [this.hoverTemplateEdge];
18539
- if (this.selectedTemplateEdge)
18540
- return [this.selectedTemplateEdge];
18543
+ if (this.hoverTemplateEdge) {
18544
+ return this.getDownstreamEdges(this.hoverTemplateEdge);
18545
+ }
18546
+ if (this.selectedTemplateEdge) {
18547
+ return [this.selectedTemplateEdge]; // Nếu chỉ click chọn thì đỏ 1 đường, hoặc bạn có thể dùng getDownstreamEdges ở đây nếu muốn
18548
+ }
18541
18549
  return [];
18542
18550
  }
18543
18551
  //#endregion
@@ -18645,8 +18653,8 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
18645
18653
  canvasHeight: this.getCanvasHeight(),
18646
18654
  nodes: this.lstTemplateNode,
18647
18655
  onPanChange: (x, y) => {
18648
- this.templateCombine.editorOption.panX = x;
18649
- this.templateCombine.editorOption.panY = y;
18656
+ this.templateCombine.editorOption.panX = Math.round(x);
18657
+ this.templateCombine.editorOption.panY = Math.round(y);
18650
18658
  },
18651
18659
  });
18652
18660
  }
@@ -19178,8 +19186,8 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
19178
19186
  const canvasX = (x - this.templateCombine.editorOption.panX) / this.zoom;
19179
19187
  const canvasY = (y - this.templateCombine.editorOption.panY) / this.zoom;
19180
19188
  this.zoom = parseFloat(newZoom.toFixed(2));
19181
- this.templateCombine.editorOption.panX = x - canvasX * this.zoom;
19182
- this.templateCombine.editorOption.panY = y - canvasY * this.zoom;
19189
+ this.templateCombine.editorOption.panX = Math.round(x - canvasX * this.zoom);
19190
+ this.templateCombine.editorOption.panY = Math.round(y - canvasY * this.zoom);
19183
19191
  this.syncminimapViewport();
19184
19192
  }
19185
19193
  // UNDO/REDO
@@ -19456,8 +19464,23 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
19456
19464
  this.selectedTemplateNode = undefined;
19457
19465
  }
19458
19466
  }
19467
+ getDownstreamEdges(startEdge) {
19468
+ const resultSet = new Set();
19469
+ const queue = [startEdge];
19470
+ while (queue.length > 0) {
19471
+ const currentEdge = queue.shift();
19472
+ // Nếu chưa có trong set thì mới xử lý (để chống lỗi vòng lặp vô hạn A->B->A)
19473
+ if (!resultSet.has(currentEdge)) {
19474
+ resultSet.add(currentEdge);
19475
+ // Tìm các cạnh tiếp theo: có From_ID bằng với To_ID của cạnh hiện tại
19476
+ const nextEdges = this.lstTemplateEdge.filter((e) => e.From_WF_Template_Id === currentEdge.To_WF_Template_Id);
19477
+ queue.push(...nextEdges);
19478
+ }
19479
+ }
19480
+ return Array.from(resultSet);
19481
+ }
19459
19482
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WF_Template_CombineEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
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" }] });
19483
+ 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: { getdata: "getdata", 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 (onSave)=\"getdata.emit()\"></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", outputs: ["onSave"] }] });
19461
19484
  }
19462
19485
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WF_Template_CombineEditorComponent, decorators: [{
19463
19486
  type: Component,
@@ -19479,29 +19502,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImpor
19479
19502
  NzInputModule,
19480
19503
  NzGridModule,
19481
19504
  NzFlexModule,
19482
- ExtendInputNumber,
19483
19505
  NzTableModule,
19484
19506
  NzDividerModule,
19485
- AutoFocusDirective,
19486
19507
  NzAutocompleteModule,
19487
- IconDelete,
19488
19508
  NzModalComponent,
19489
19509
  NzModalContentDirective,
19490
- NzModalTitleDirective,
19491
- IconAdd,
19492
- NzModalFooterDirective,
19493
- DicDomainSelectComponent$1,
19494
- IconInfo,
19495
19510
  WF_TemplateDetail,
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"] }]
19511
+ ], 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 (onSave)=\"getdata.emit()\"></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"] }]
19497
19512
  }], propDecorators: { lstTemplateForSelect: [{
19498
19513
  type: Input
19514
+ }], getdata: [{
19515
+ type: Output
19499
19516
  }], onSave: [{
19500
- type: Output,
19501
- args: ['onSave']
19517
+ type: Output
19502
19518
  }], onDeleteTempldateNode: [{
19503
- type: Output,
19504
- args: ['onDeleteTempldateNode']
19519
+ type: Output
19505
19520
  }], canvasRef: [{
19506
19521
  type: ViewChild,
19507
19522
  args: ['canvas', { static: true }]
@@ -19523,10 +19538,12 @@ class WF_Template_CombineDetailComponent extends BaseComponent {
19523
19538
  wfeditor;
19524
19539
  ngOnInit() {
19525
19540
  this.updateBC();
19526
- const id = this.getUrlParam('id');
19527
- this.getData(id);
19541
+ this.getData();
19528
19542
  }
19529
19543
  getData(id) {
19544
+ id = id || this.getUrlParam('id');
19545
+ if (!id)
19546
+ return;
19530
19547
  this.service.getLstTemplate().then((res) => (this.lstTemplate = res.Data));
19531
19548
  this.service.getWFCombine(id).then((res) => {
19532
19549
  this.templateCombine = new WFTemplate_Combine(res.Data);
@@ -19571,11 +19588,11 @@ class WF_Template_CombineDetailComponent extends BaseComponent {
19571
19588
  });
19572
19589
  }
19573
19590
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WF_Template_CombineDetailComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
19574
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.7", type: WF_Template_CombineDetailComponent, isStandalone: true, selector: "ng-component", viewQueries: [{ propertyName: "wfeditor", first: true, predicate: ["wfeditor"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"workflow-wrapper\" style=\"height: calc(100vh - 110px)\">\n <app-workflow-combine-editor\n #wfeditor\n [lstTemplateForSelect]=\"lstTemplate\"\n (onSave)=\"save($event)\"\n (onDeleteTempldateNode)=\"deleteTempldateNode($event)\"\n ></app-workflow-combine-editor>\n</div>\n\n<!-- (onDeleteStage)=\"deleteStage($event)\"\n (onDeleteAction)=\"deleteAction($event)\"\n (onDeleteRule)=\"deleteRule($event)\"\n (onDeleteRuleLine)=\"deleteRuleLine($event)\"\n (onCheckRule)=\"onCheckRule($event)\"\n (onCheckAllRule)=\"onCheckAllRule($event)\" -->\n", styles: [".workflow-wrapper{position:relative}\n"], dependencies: [{ kind: "component", type: WF_Template_CombineEditorComponent, selector: "app-workflow-combine-editor", inputs: ["lstTemplateForSelect"], outputs: ["onSave", "onDeleteTempldateNode"] }] });
19591
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.7", type: WF_Template_CombineDetailComponent, isStandalone: true, selector: "ng-component", viewQueries: [{ propertyName: "wfeditor", first: true, predicate: ["wfeditor"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"workflow-wrapper\" style=\"height: calc(100vh - 110px)\">\n <app-workflow-combine-editor\n #wfeditor\n [lstTemplateForSelect]=\"lstTemplate\"\n (onSave)=\"save($event)\"\n (getdata)=\"getData()\"\n (onDeleteTempldateNode)=\"deleteTempldateNode($event)\"\n ></app-workflow-combine-editor>\n</div>\n", styles: [".workflow-wrapper{position:relative}\n"], dependencies: [{ kind: "component", type: WF_Template_CombineEditorComponent, selector: "app-workflow-combine-editor", inputs: ["lstTemplateForSelect"], outputs: ["getdata", "onSave", "onDeleteTempldateNode"] }] });
19575
19592
  }
19576
19593
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WF_Template_CombineDetailComponent, decorators: [{
19577
19594
  type: Component,
19578
- args: [{ imports: [WF_Template_CombineEditorComponent], template: "<div class=\"workflow-wrapper\" style=\"height: calc(100vh - 110px)\">\n <app-workflow-combine-editor\n #wfeditor\n [lstTemplateForSelect]=\"lstTemplate\"\n (onSave)=\"save($event)\"\n (onDeleteTempldateNode)=\"deleteTempldateNode($event)\"\n ></app-workflow-combine-editor>\n</div>\n\n<!-- (onDeleteStage)=\"deleteStage($event)\"\n (onDeleteAction)=\"deleteAction($event)\"\n (onDeleteRule)=\"deleteRule($event)\"\n (onDeleteRuleLine)=\"deleteRuleLine($event)\"\n (onCheckRule)=\"onCheckRule($event)\"\n (onCheckAllRule)=\"onCheckAllRule($event)\" -->\n", styles: [".workflow-wrapper{position:relative}\n"] }]
19595
+ args: [{ imports: [WF_Template_CombineEditorComponent], template: "<div class=\"workflow-wrapper\" style=\"height: calc(100vh - 110px)\">\n <app-workflow-combine-editor\n #wfeditor\n [lstTemplateForSelect]=\"lstTemplate\"\n (onSave)=\"save($event)\"\n (getdata)=\"getData()\"\n (onDeleteTempldateNode)=\"deleteTempldateNode($event)\"\n ></app-workflow-combine-editor>\n</div>\n", styles: [".workflow-wrapper{position:relative}\n"] }]
19579
19596
  }], propDecorators: { wfeditor: [{
19580
19597
  type: ViewChild,
19581
19598
  args: ['wfeditor']