@brggroup/share-lib 0.1.73 → 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.
- package/fesm2022/brggroup-share-lib.mjs +117 -81
- package/fesm2022/brggroup-share-lib.mjs.map +1 -1
- package/lib/WF/wf-combine/wf-template-combine-detail.d.ts +1 -1
- package/lib/WF/wf-combine/wf-template-combine-detail.d.ts.map +1 -1
- package/lib/WF/wf-combine/workflow-editor-combine/detail/wf-template.detail.d.ts +3 -2
- package/lib/WF/wf-combine/workflow-editor-combine/detail/wf-template.detail.d.ts.map +1 -1
- package/lib/WF/wf-combine/workflow-editor-combine/workflow-editor-combine.d.ts +11 -1
- package/lib/WF/wf-combine/workflow-editor-combine/workflow-editor-combine.d.ts.map +1 -1
- package/lib/admin/service/file.service.d.ts +0 -1
- package/lib/admin/service/file.service.d.ts.map +1 -1
- package/lib/admin/service/sequence.service.d.ts.map +1 -1
- package/lib/auth/auth.service.d.ts +3 -0
- package/lib/auth/auth.service.d.ts.map +1 -1
- package/lib/auth/permission.service.d.ts +1 -2
- package/lib/auth/permission.service.d.ts.map +1 -1
- package/lib/components/extend/extend-view-file.d.ts +2 -1
- package/lib/components/extend/extend-view-file.d.ts.map +1 -1
- package/lib/components/layout/header/user/user.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -670,6 +670,7 @@ const URLs$j = {
|
|
|
670
670
|
changePassword: '/api/Auth/ChangePassword',
|
|
671
671
|
setPass: '/api/Auth/SetPass',
|
|
672
672
|
changeOrgLogin: '/api/Auth/changeOrgLogin',
|
|
673
|
+
getUserPermission: '/api/Auth/getUserPermission',
|
|
673
674
|
};
|
|
674
675
|
class AuthService extends HTTPService {
|
|
675
676
|
notiService = inject(NotiService);
|
|
@@ -762,6 +763,15 @@ class AuthService extends HTTPService {
|
|
|
762
763
|
return false;
|
|
763
764
|
}
|
|
764
765
|
}
|
|
766
|
+
async getUserPermission() {
|
|
767
|
+
try {
|
|
768
|
+
const res = await this.get(AppGlobals.apiEndpoint + URLs$j.getUserPermission, true);
|
|
769
|
+
return res.Data;
|
|
770
|
+
}
|
|
771
|
+
catch {
|
|
772
|
+
return null;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
765
775
|
/* ----------------------------------------
|
|
766
776
|
MENU
|
|
767
777
|
---------------------------------------- */
|
|
@@ -907,8 +917,7 @@ function checkRole(user, expectedRole) {
|
|
|
907
917
|
}
|
|
908
918
|
|
|
909
919
|
let PermissionService$1 = class PermissionService {
|
|
910
|
-
|
|
911
|
-
cms = inject(CommonService);
|
|
920
|
+
authService = inject(AuthService);
|
|
912
921
|
currentUser$ = new BehaviorSubject(null);
|
|
913
922
|
// Hứng luật từ App. Nếu App không truyền thì lấy object rỗng {}
|
|
914
923
|
appRules = inject(ABAC_RULES_TOKEN, { optional: true }) || {};
|
|
@@ -916,41 +925,16 @@ let PermissionService$1 = class PermissionService {
|
|
|
916
925
|
this.currentUser$.next(user);
|
|
917
926
|
}
|
|
918
927
|
async getUserPermission() {
|
|
919
|
-
// 1. Caching: Đã có data rồi thì thôi không gọi nữa
|
|
920
|
-
if (this.currentUser$.value)
|
|
921
|
-
return true;
|
|
922
928
|
try {
|
|
923
|
-
let
|
|
924
|
-
|
|
925
|
-
};
|
|
926
|
-
let ret = await this.cms.ESP(data);
|
|
927
|
-
if (ret && ret.IsSuccess && ret.Data) {
|
|
928
|
-
// 2. Xử lý an toàn các mảng chuỗi (Split, Trim, Filter)
|
|
929
|
-
const parseStringToArray = (str) => {
|
|
930
|
-
if (!str)
|
|
931
|
-
return [];
|
|
932
|
-
return str
|
|
933
|
-
.split(',')
|
|
934
|
-
.map((item) => item.trim()) // Xóa khoảng trắng thừa
|
|
935
|
-
.filter((item) => item.length > 0); // Bỏ các phần tử rỗng
|
|
936
|
-
};
|
|
937
|
-
let user = {
|
|
938
|
-
id: ret.Data.userid || '',
|
|
939
|
-
username: ret.Data.username || '',
|
|
940
|
-
roles: parseStringToArray(ret.Data.roles),
|
|
941
|
-
permissions: parseStringToArray(ret.Data.permissions),
|
|
942
|
-
};
|
|
943
|
-
this.setCurrentUser(user);
|
|
944
|
-
return true;
|
|
945
|
-
}
|
|
946
|
-
else {
|
|
947
|
-
console.warn('Không lấy được thông tin quyền của User');
|
|
929
|
+
let user = await this.authService.getUserPermission();
|
|
930
|
+
if (!user)
|
|
948
931
|
return false;
|
|
949
|
-
|
|
932
|
+
this.setCurrentUser(user);
|
|
933
|
+
return true;
|
|
950
934
|
}
|
|
951
935
|
catch (error) {
|
|
952
936
|
console.error('Lỗi API khi lấy quyền User:', error);
|
|
953
|
-
return false;
|
|
937
|
+
return false;
|
|
954
938
|
}
|
|
955
939
|
}
|
|
956
940
|
hasAccess(resource, action, data) {
|
|
@@ -7943,12 +7927,6 @@ class FileService extends HTTPService {
|
|
|
7943
7927
|
moveFileToDisk(obj) {
|
|
7944
7928
|
return this.postData(AppGlobals.apiEndpoint + URLs$c.moveFileToDisk, obj);
|
|
7945
7929
|
}
|
|
7946
|
-
getPaging_HDSD(filter) {
|
|
7947
|
-
return this.cms.ESP({
|
|
7948
|
-
SPN: 'App_File_getpaging_HDSD',
|
|
7949
|
-
Params: [filter],
|
|
7950
|
-
});
|
|
7951
|
-
}
|
|
7952
7930
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: FileService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
7953
7931
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: FileService, providedIn: 'root' });
|
|
7954
7932
|
}
|
|
@@ -9285,10 +9263,7 @@ class SequenceService extends HTTPService {
|
|
|
9285
9263
|
return this.postData(AppGlobals.apiEndpoint + URLs$9.getList, filter);
|
|
9286
9264
|
}
|
|
9287
9265
|
getPaging(filter) {
|
|
9288
|
-
return this.
|
|
9289
|
-
SPN: 'App_Sequence_getPaging',
|
|
9290
|
-
Params: [filter],
|
|
9291
|
-
});
|
|
9266
|
+
return this.postData(AppGlobals.apiEndpoint + URLs$9.getPaging, filter);
|
|
9292
9267
|
}
|
|
9293
9268
|
addOrEdit(obj) {
|
|
9294
9269
|
return this.commonService.ESP({
|
|
@@ -11402,8 +11377,8 @@ let WorkflowEditorOption$1 = class WorkflowEditorOption {
|
|
|
11402
11377
|
AllowbackInUse;
|
|
11403
11378
|
constructor(obj) {
|
|
11404
11379
|
obj = obj || {};
|
|
11405
|
-
this.panX = obj.panX || 0;
|
|
11406
|
-
this.panY = obj.panY || 0;
|
|
11380
|
+
this.panX = Math.round(obj.panX) || 0;
|
|
11381
|
+
this.panY = Math.round(obj.panY) || 0;
|
|
11407
11382
|
this.AllowbackInUse = obj.AllowbackInUse || false;
|
|
11408
11383
|
}
|
|
11409
11384
|
};
|
|
@@ -11816,8 +11791,8 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
11816
11791
|
canvasHeight: this.getCanvasHeight(),
|
|
11817
11792
|
nodes: this.lstStage, // Truyền trực tiếp mảng dữ liệu Node
|
|
11818
11793
|
onPanChange: (x, y) => {
|
|
11819
|
-
this.template.editorOption.panX = x;
|
|
11820
|
-
this.template.editorOption.panY = y;
|
|
11794
|
+
this.template.editorOption.panX = Math.round(x);
|
|
11795
|
+
this.template.editorOption.panY = Math.round(y);
|
|
11821
11796
|
},
|
|
11822
11797
|
});
|
|
11823
11798
|
}
|
|
@@ -12772,8 +12747,8 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
12772
12747
|
const canvasY = (y - this.template.editorOption.panY) / this.zoom;
|
|
12773
12748
|
this.zoom = parseFloat(newZoom.toFixed(2));
|
|
12774
12749
|
// Tính toán lại vị trí Pan để điểm đang trỏ vẫn nằm dưới chuột
|
|
12775
|
-
this.template.editorOption.panX = x - canvasX * this.zoom;
|
|
12776
|
-
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);
|
|
12777
12752
|
this.syncMiniMapViewport();
|
|
12778
12753
|
}
|
|
12779
12754
|
//#endregion
|
|
@@ -14619,11 +14594,9 @@ class LayoutUser extends BaseComponent {
|
|
|
14619
14594
|
if (this.hdsdData)
|
|
14620
14595
|
return; // Nếu đã load rồi thì không load lại
|
|
14621
14596
|
const filter = new FileFilter();
|
|
14622
|
-
filter.PageIndex = 0;
|
|
14623
|
-
filter.PageSize = 100;
|
|
14624
14597
|
filter.Code = 'HDSD';
|
|
14625
14598
|
this.loadingHDSD = true;
|
|
14626
|
-
this.fileService.
|
|
14599
|
+
this.fileService.getPaging(filter).then((res) => {
|
|
14627
14600
|
this.hdsdData = res.Data;
|
|
14628
14601
|
this.loadingHDSD = false;
|
|
14629
14602
|
}, (err) => {
|
|
@@ -18172,6 +18145,7 @@ class WF_TemplateDetail extends BaseComponent {
|
|
|
18172
18145
|
lstAction = [];
|
|
18173
18146
|
lstActionRef = [];
|
|
18174
18147
|
wfeditor;
|
|
18148
|
+
onSave = new EventEmitter();
|
|
18175
18149
|
ngOnInit() {
|
|
18176
18150
|
this.getMasterData();
|
|
18177
18151
|
}
|
|
@@ -18241,6 +18215,7 @@ class WF_TemplateDetail extends BaseComponent {
|
|
|
18241
18215
|
.then((res) => {
|
|
18242
18216
|
this.notiService.success();
|
|
18243
18217
|
this.getData(res.Data);
|
|
18218
|
+
this.onSave.emit();
|
|
18244
18219
|
}, (err) => {
|
|
18245
18220
|
this.handleError(err);
|
|
18246
18221
|
this.wfeditor.ready = true;
|
|
@@ -18306,7 +18281,7 @@ class WF_TemplateDetail extends BaseComponent {
|
|
|
18306
18281
|
this.wfeditor.actionRuleModalVisible = false;
|
|
18307
18282
|
}
|
|
18308
18283
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WF_TemplateDetail, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
18309
|
-
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"] }] });
|
|
18310
18285
|
}
|
|
18311
18286
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WF_TemplateDetail, decorators: [{
|
|
18312
18287
|
type: Component,
|
|
@@ -18314,6 +18289,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImpor
|
|
|
18314
18289
|
}], propDecorators: { wfeditor: [{
|
|
18315
18290
|
type: ViewChild,
|
|
18316
18291
|
args: ['wfeditor']
|
|
18292
|
+
}], onSave: [{
|
|
18293
|
+
type: Output
|
|
18317
18294
|
}] } });
|
|
18318
18295
|
|
|
18319
18296
|
//#region MODELS
|
|
@@ -18399,8 +18376,8 @@ class WorkflowEditorOption {
|
|
|
18399
18376
|
AllowbackInUse;
|
|
18400
18377
|
constructor(obj) {
|
|
18401
18378
|
obj = obj || {};
|
|
18402
|
-
this.panX = obj.panX || 0;
|
|
18403
|
-
this.panY = obj.panY || 0;
|
|
18379
|
+
this.panX = Math.round(obj.panX) || 0;
|
|
18380
|
+
this.panY = Math.round(obj.panY) || 0;
|
|
18404
18381
|
this.AllowbackInUse = obj.AllowbackInUse || false;
|
|
18405
18382
|
}
|
|
18406
18383
|
}
|
|
@@ -18469,6 +18446,10 @@ class WorkflowTemplateEdge {
|
|
|
18469
18446
|
Id;
|
|
18470
18447
|
From_WF_Template_Id;
|
|
18471
18448
|
To_WF_Template_Id;
|
|
18449
|
+
From_WF_TemplateStage_Id;
|
|
18450
|
+
To_WF_TemplateStage_Id;
|
|
18451
|
+
From_WF_TemplateStageAction_Id;
|
|
18452
|
+
To_WF_TemplateStageAction_Id;
|
|
18472
18453
|
FromStage;
|
|
18473
18454
|
ToStage;
|
|
18474
18455
|
FromAction;
|
|
@@ -18479,6 +18460,10 @@ class WorkflowTemplateEdge {
|
|
|
18479
18460
|
this.Id = obj.Id || Date.now().toString();
|
|
18480
18461
|
this.From_WF_Template_Id = obj.From_WF_Template_Id || null;
|
|
18481
18462
|
this.To_WF_Template_Id = obj.To_WF_Template_Id || null;
|
|
18463
|
+
this.From_WF_TemplateStage_Id = obj.From_WF_TemplateStage_Id || null;
|
|
18464
|
+
this.To_WF_TemplateStage_Id = obj.To_WF_TemplateStage_Id || null;
|
|
18465
|
+
this.From_WF_TemplateStageAction_Id = obj.From_WF_TemplateStageAction_Id || null;
|
|
18466
|
+
this.To_WF_TemplateStageAction_Id = obj.To_WF_TemplateStageAction_Id || null;
|
|
18482
18467
|
this.FromStage = obj.FromStage || '';
|
|
18483
18468
|
this.ToStage = obj.ToStage || '';
|
|
18484
18469
|
this.FromAction = obj.FromAction || '';
|
|
@@ -18489,6 +18474,7 @@ class WorkflowTemplateEdge {
|
|
|
18489
18474
|
//#endregion MODELS
|
|
18490
18475
|
class WF_Template_CombineEditorComponent extends BaseComponent {
|
|
18491
18476
|
lstTemplateForSelect = [];
|
|
18477
|
+
getdata = new EventEmitter();
|
|
18492
18478
|
onSave = new EventEmitter();
|
|
18493
18479
|
onDeleteTempldateNode = new EventEmitter();
|
|
18494
18480
|
lstTemplateSelected = [];
|
|
@@ -18524,6 +18510,7 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
|
|
|
18524
18510
|
draggingGroup = false;
|
|
18525
18511
|
dragStartMouse;
|
|
18526
18512
|
dragStartPositions = new Map();
|
|
18513
|
+
dragStartEdgePoints = new Map();
|
|
18527
18514
|
draggingNode;
|
|
18528
18515
|
isDragging = false;
|
|
18529
18516
|
dragStartX = 0;
|
|
@@ -18549,13 +18536,16 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
|
|
|
18549
18536
|
svgRef;
|
|
18550
18537
|
wftemplatedetail;
|
|
18551
18538
|
get normalEdges() {
|
|
18552
|
-
|
|
18539
|
+
const hoveredSet = new Set(this.hoverEdges);
|
|
18540
|
+
return this.lstTemplateEdge.filter((e) => !hoveredSet.has(e));
|
|
18553
18541
|
}
|
|
18554
18542
|
get hoverEdges() {
|
|
18555
|
-
if (this.hoverTemplateEdge)
|
|
18556
|
-
return
|
|
18557
|
-
|
|
18558
|
-
|
|
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
|
+
}
|
|
18559
18549
|
return [];
|
|
18560
18550
|
}
|
|
18561
18551
|
//#endregion
|
|
@@ -18663,8 +18653,8 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
|
|
|
18663
18653
|
canvasHeight: this.getCanvasHeight(),
|
|
18664
18654
|
nodes: this.lstTemplateNode,
|
|
18665
18655
|
onPanChange: (x, y) => {
|
|
18666
|
-
this.templateCombine.editorOption.panX = x;
|
|
18667
|
-
this.templateCombine.editorOption.panY = y;
|
|
18656
|
+
this.templateCombine.editorOption.panX = Math.round(x);
|
|
18657
|
+
this.templateCombine.editorOption.panY = Math.round(y);
|
|
18668
18658
|
},
|
|
18669
18659
|
});
|
|
18670
18660
|
}
|
|
@@ -18776,6 +18766,7 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
|
|
|
18776
18766
|
const snap = this.snapPoint({ x: this.dragStartMouse.x + dx, y: this.dragStartMouse.y + dy }, event);
|
|
18777
18767
|
const sdx = snap.x - this.dragStartMouse.x;
|
|
18778
18768
|
const sdy = snap.y - this.dragStartMouse.y;
|
|
18769
|
+
// 1. Cập nhật vị trí mới cho các Nodes
|
|
18779
18770
|
for (const n of this.lstTemplateNode) {
|
|
18780
18771
|
if (!this.lstSelectedTemplateId.has(n.WF_Template_Id))
|
|
18781
18772
|
continue;
|
|
@@ -18783,6 +18774,15 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
|
|
|
18783
18774
|
n.editorOption.x = start.x + sdx;
|
|
18784
18775
|
n.editorOption.y = start.y + sdy;
|
|
18785
18776
|
}
|
|
18777
|
+
// 2. Cập nhật vị trí mới cho các Waypoint đi kèm
|
|
18778
|
+
this.dragStartEdgePoints.forEach((startPoints, edge) => {
|
|
18779
|
+
if (edge.editorOption.points) {
|
|
18780
|
+
for (let i = 0; i < startPoints.length; i++) {
|
|
18781
|
+
edge.editorOption.points[i].x = startPoints[i].x + sdx;
|
|
18782
|
+
edge.editorOption.points[i].y = startPoints[i].y + sdy;
|
|
18783
|
+
}
|
|
18784
|
+
}
|
|
18785
|
+
});
|
|
18786
18786
|
return;
|
|
18787
18787
|
}
|
|
18788
18788
|
if (this.draggingNode) {
|
|
@@ -18847,18 +18847,33 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
|
|
|
18847
18847
|
return;
|
|
18848
18848
|
this.axisLock = null;
|
|
18849
18849
|
const p = this.getSvgPoint(event);
|
|
18850
|
+
// KÉO THẢ NHIỀU NODE (GROUP)
|
|
18850
18851
|
if (this.lstSelectedTemplateId.has(node.WF_Template_Id)) {
|
|
18851
18852
|
this.pushUndo({ type: 'move-nodes', before: this.cloneNodePositions(this.lstSelectedTemplateId) });
|
|
18852
18853
|
this.draggingGroup = true;
|
|
18853
18854
|
this.dragStartMouse = p;
|
|
18854
18855
|
this.dragStartPositions.clear();
|
|
18856
|
+
this.dragStartEdgePoints.clear(); // Xóa dữ liệu cũ
|
|
18857
|
+
// 1. Lưu vị trí ban đầu của các Node được chọn
|
|
18855
18858
|
for (const n of this.lstTemplateNode) {
|
|
18856
18859
|
if (this.lstSelectedTemplateId.has(n.WF_Template_Id)) {
|
|
18857
18860
|
this.dragStartPositions.set(n.WF_Template_Id, { x: n.editorOption.x, y: n.editorOption.y });
|
|
18858
18861
|
}
|
|
18859
18862
|
}
|
|
18863
|
+
// 2. Lưu vị trí ban đầu của các Waypoint (điểm bẻ cong) thuộc các đường nối nội bộ
|
|
18864
|
+
for (const edge of this.lstTemplateEdge) {
|
|
18865
|
+
if (this.lstSelectedTemplateId.has(edge.From_WF_Template_Id) &&
|
|
18866
|
+
this.lstSelectedTemplateId.has(edge.To_WF_Template_Id) &&
|
|
18867
|
+
edge.editorOption.points &&
|
|
18868
|
+
edge.editorOption.points.length > 0) {
|
|
18869
|
+
// Clone mảng tọa độ waypoint ra để lưu
|
|
18870
|
+
const clonedPoints = edge.editorOption.points.map((pt) => ({ x: pt.x, y: pt.y }));
|
|
18871
|
+
this.dragStartEdgePoints.set(edge, clonedPoints);
|
|
18872
|
+
}
|
|
18873
|
+
}
|
|
18860
18874
|
return;
|
|
18861
18875
|
}
|
|
18876
|
+
// KÉO THẢ 1 NODE
|
|
18862
18877
|
this.lstSelectedTemplateId.clear();
|
|
18863
18878
|
this.hoverTemplateNode = undefined;
|
|
18864
18879
|
this.pushUndo({ type: 'move-nodes', before: this.cloneNodePositions(new Set([node.WF_Template_Id])) });
|
|
@@ -19171,8 +19186,8 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
|
|
|
19171
19186
|
const canvasX = (x - this.templateCombine.editorOption.panX) / this.zoom;
|
|
19172
19187
|
const canvasY = (y - this.templateCombine.editorOption.panY) / this.zoom;
|
|
19173
19188
|
this.zoom = parseFloat(newZoom.toFixed(2));
|
|
19174
|
-
this.templateCombine.editorOption.panX = x - canvasX * this.zoom;
|
|
19175
|
-
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);
|
|
19176
19191
|
this.syncminimapViewport();
|
|
19177
19192
|
}
|
|
19178
19193
|
// UNDO/REDO
|
|
@@ -19229,12 +19244,24 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
|
|
|
19229
19244
|
if (this.lstSelectedTemplateId.size === 0)
|
|
19230
19245
|
return;
|
|
19231
19246
|
this.pushUndo({ type: 'move-nodes', before: this.cloneNodePositions(this.lstSelectedTemplateId) });
|
|
19247
|
+
// 1. Di chuyển các Node
|
|
19232
19248
|
for (const n of this.lstTemplateNode) {
|
|
19233
19249
|
if (!this.lstSelectedTemplateId.has(n.WF_Template_Id))
|
|
19234
19250
|
continue;
|
|
19235
19251
|
n.editorOption.x = this.clamp(n.editorOption.x + dx, 0, this.getCanvasWidth() - this.NODE_WIDTH);
|
|
19236
19252
|
n.editorOption.y = this.clamp(n.editorOption.y + dy, 0, this.getCanvasHeight() - this.NODE_HEIGHT);
|
|
19237
19253
|
}
|
|
19254
|
+
// 2. Di chuyển các Waypoint của đường nối nội bộ
|
|
19255
|
+
for (const edge of this.lstTemplateEdge) {
|
|
19256
|
+
if (this.lstSelectedTemplateId.has(edge.From_WF_Template_Id) &&
|
|
19257
|
+
this.lstSelectedTemplateId.has(edge.To_WF_Template_Id) &&
|
|
19258
|
+
edge.editorOption.points) {
|
|
19259
|
+
for (const pt of edge.editorOption.points) {
|
|
19260
|
+
pt.x += dx;
|
|
19261
|
+
pt.y += dy;
|
|
19262
|
+
}
|
|
19263
|
+
}
|
|
19264
|
+
}
|
|
19238
19265
|
}
|
|
19239
19266
|
// ALIGNMENT
|
|
19240
19267
|
getSelectedNodes() {
|
|
@@ -19437,8 +19464,23 @@ class WF_Template_CombineEditorComponent extends BaseComponent {
|
|
|
19437
19464
|
this.selectedTemplateNode = undefined;
|
|
19438
19465
|
}
|
|
19439
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
|
+
}
|
|
19440
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 });
|
|
19441
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: WF_Template_CombineEditorComponent, isStandalone: true, selector: "app-workflow-combine-editor", inputs: { lstTemplateForSelect: "lstTemplateForSelect" }, outputs: { onSave: "onSave", onDeleteTempldateNode: "onDeleteTempldateNode" }, host: { listeners: { "window:keydown": "onKeyDown($event)" } }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true, static: true }, { propertyName: "svgRef", first: true, predicate: ["svg"], descendants: true, static: true }, { propertyName: "wftemplatedetail", first: true, predicate: ["wftemplatedetail"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div\n #canvas\n class=\"workflow-canvas\"\n [class.connecting]=\"!!connectingFrom\"\n [class.dragging-point]=\"!!draggingPoint\"\n style=\"width: 100%; height: 100%\"\n (mousedown)=\"onMouseDownCanvas($event)\"\n (mousemove)=\"onMouseMoveCanvas($event)\"\n (mouseup)=\"onMouseUpCanvas($event)\"\n (click)=\"onClickCanvas($event)\"\n (wheel)=\"onWheelCanvas($event)\"\n>\n <!-- TOOLBAR -->\n <div class=\"toolbar\" (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\n <button nz-button nzSize=\"small\" nz-tooltip=\"Editor setting\" (click)=\"settingVisible = true\">\n <nz-icon nzType=\"setting\"></nz-icon>\n </button>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Infomation\" (click)=\"infoVisible = true\">\n <nz-icon nzType=\"info-circle\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Global Setting\" (click)=\"drawTemplateVisibel = true\">\n <nz-icon nzType=\"setting\"></nz-icon> G\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nzDanger [nzLoading]=\"!ready\" nz-tooltip=\"Save (Ctrl + S)\" (click)=\"save()\">\n <nz-icon nzType=\"save\"></nz-icon>\n </button>\n <button nz-button nzSize=\"small\" nz-tooltip=\"Th\u00EAm Template m\u1EDBi\" (click)=\"isModalVisible = true\">\n <nz-icon nzType=\"plus\" class=\"color-primary\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Move mode\"\n (click)=\"isMoveMode = true\"\n >\n <nz-icon><img src=\"/assets/icon/hand-palm.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"!isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Select mode\"\n (click)=\"isMoveMode = false\"\n >\n <nz-icon><img src=\"/assets/icon/cursor.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- UNDO / REDO -->\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"undoStack.length === 0\"\n nz-tooltip=\"Undo\"\n (click)=\"undo()\"\n >\n <nz-icon nzType=\"undo\"></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"redoStack.length === 0\"\n nz-tooltip=\"Redo\"\n (click)=\"redo()\"\n >\n <nz-icon nzType=\"redo\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ALIGN -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignLeft()\">\u27F8</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignCenter()\">\u2261</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignRight()\">\u27F9</button>\n <span class=\"divider\"></span>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignTop()\">\u21D1</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignMiddle()\">\u2550</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignBottom()\">\u21D3</button>\n <span class=\"divider\"></span>\n <!-- DISTRIBUTE -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 3\" (click)=\"distributeHorizontal()\">\n \u21C4\n </button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 3\" (click)=\"distributeVertical()\">\n \u21C5\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ZOOM -->\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"zoomOut()\" nz-tooltip=\"Zoom Out\">\n <nz-icon nzType=\"minus\"></nz-icon>\n </button>\n <span>{{ Math.round(zoom * 100) }}%</span>\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"zoomIn()\" nz-tooltip=\"Zoom In\">\n <nz-icon nzType=\"plus\"></nz-icon>\n </button>\n <span class=\"divider\"></span>\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"resetZoom()\" nz-tooltip=\"Reset Zoom (Ctrl+0)\">\n <nz-icon nzType=\"expand\"></nz-icon>\n </button>\n </div>\n\n <div\n class=\"canvas-content\"\n [class.panning]=\"isMoveMode\"\n [style.width.px]=\"getCanvasWidth()\"\n [style.height.px]=\"getCanvasHeight()\"\n [style.transform]=\"\n 'translate(' +\n templateCombine.editorOption.panX +\n 'px,' +\n templateCombine.editorOption.panY +\n 'px) scale(' +\n zoom +\n ')'\n \"\n >\n <!-- GRID -->\n <div *ngIf=\"wfcSetting.ShowGrid\" class=\"grid-layer\"></div>\n\n <!-- SVG EDGES -->\n <svg #svg class=\"edges-layer\" width=\"100%\" height=\"100%\" preserveAspectRatio=\"none\">\n <g>\n <!-- DEFS -->\n <defs>\n <filter id=\"edge-glow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n <feGaussianBlur stdDeviation=\"2\" result=\"blur\" />\n <feMerge>\n <feMergeNode in=\"blur\" />\n <feMergeNode in=\"SourceGraphic\" />\n </feMerge>\n </filter>\n\n <marker\n id=\"arrow-blue\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n <marker\n id=\"arrow-red\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n </defs>\n\n <!-- EDGES B\u00CCNH TH\u01AF\u1EDCNG -->\n <ng-container *ngFor=\"let e of normalEdges; let i = index\">\n <path class=\"edge\" [attr.id]=\"'edge-path-' + i\" [attr.d]=\"buildPath(e)\" marker-end=\"url(#arrow-blue)\"></path>\n\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseenter)=\"onMouseEnterEdge(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <!-- \u0110\u00E3 x\u00F3a *ngIf=\"e.RuleLineDetails?.length\" \u1EDF \u0111\u00E2y \u0111\u1EC3 text lu\u00F4n hi\u1EC7n -->\n <text\n class=\"edge-label\"\n style=\"fill: #1890ff; font-weight: 500\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.FromStage }} > {{ e.FromAction }}\n </text>\n </ng-container>\n\n <!-- EDGE \u0110ANG HOVER/SELECTED (HI\u1EC2N TH\u1ECA M\u00C0U \u0110\u1ECE) -->\n <ng-container *ngFor=\"let e of hoverEdges; let i = index\">\n <path\n class=\"edge red\"\n [attr.id]=\"'edge-path-hover-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-red)\"\n ></path>\n\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <text\n class=\"edge-label\"\n style=\"font-weight: bold; fill: red\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.FromStage }} > {{ e.FromAction }}\n </text>\n </ng-container>\n\n <!-- PREVIEW LINE (\u0110\u01AF\u1EDCNG N\u1ED0I \u0110ANG K\u00C9O) -->\n <path\n *ngIf=\"connectingFrom\"\n class=\"edge\"\n [attr.d]=\"buildPreviewPath()\"\n stroke-dasharray=\"5,5\"\n marker-end=\"url(#arrow-blue)\"\n ></path>\n </g>\n </svg>\n\n <!-- BOX V\u00D9NG CH\u1ECCN MULTI -->\n <div\n *ngIf=\"isSelecting && selectStart && selectEnd\"\n class=\"selection-box\"\n [style.left.px]=\"Math.min(selectStart.x, selectEnd.x)\"\n [style.top.px]=\"Math.min(selectStart.y, selectEnd.y)\"\n [style.width.px]=\"Math.abs(selectEnd.x - selectStart.x)\"\n [style.height.px]=\"Math.abs(selectEnd.y - selectStart.y)\"\n ></div>\n\n <!-- NODE (TEMPLATE) L\u1EDAP HI\u1EC2N TH\u1ECA TR\u00CAN C\u00D9NG -->\n @for (n of lstTemplateNode; track n.WF_Template_Id) {\n <nz-card\n class=\"workflow-node\"\n [attr.data-id]=\"n.Code\"\n [class.selected]=\"\n n == selectedTemplateNode || n == hoverTemplateNode || lstSelectedTemplateId.has(n.WF_Template_Id)\n \"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n) || isDraggingFrom(n) || isSelectedNode(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickNode(n)\"\n >\n <div class=\"title\" style=\"color: #1890ff; display: flex; justify-content: space-between; align-items: center\">\n <span>{{ n.Code }}</span>\n <nz-icon nzType=\"layout\" nzTheme=\"outline\"></nz-icon>\n </div>\n <div\n style=\"\n font-size: 12px;\n line-height: 1.2;\n font-weight: 500;\n height: 28px;\n overflow: hidden;\n text-overflow: ellipsis;\n \"\n >\n {{ n.Name || \"Ch\u01B0a c\u00F3 t\u00EAn\" }}\n </div>\n <div style=\"font-size: 10px; color: gray; margin-top: 4px\">\n {{ n.DocType }}\n </div>\n\n <!-- CONNECTOR \u0110\u1EC2 K\u00C9O D\u00C2Y -->\n <div class=\"connector connector-right\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n <div class=\"connector connector-left\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n </nz-card>\n }\n\n <!-- C\u00C1C \u0110I\u1EC2M WAYPOINT \u0110\u1EC2 B\u1EBA CONG D\u00C2Y CHU\u1ED8T -->\n @for (p of connectingPoints; track $index) {\n @if (p != draggingPoint) {\n <div\n class=\"waypoint\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n (contextmenu)=\"onRightClickPoint($event, hoverTemplateEdge!, $index)\"\n ></div>\n } @else {\n <div\n class=\"waypoint dragging\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n ></div>\n }\n }\n </div>\n</div>\n\n<!-- ==============================================\n 1. DRAWER: GLOBAL TEMPLATE SETTINGS \n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawTemplateTitle\"\n nzPlacement=\"right\"\n [nzWidth]=\"500\"\n [nzClosable]=\"false\"\n [nzVisible]=\"drawTemplateVisibel\"\n [nzFooter]=\"footerTplTemplate\"\n (nzOnClose)=\"drawTemplateVisibel = false\"\n>\n <ng-template #drawTemplateTitle> <nz-icon nzType=\"global\"></nz-icon> 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> 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> 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> 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> 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> 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"] }] });
|
|
19442
19484
|
}
|
|
19443
19485
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WF_Template_CombineEditorComponent, decorators: [{
|
|
19444
19486
|
type: Component,
|
|
@@ -19460,29 +19502,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImpor
|
|
|
19460
19502
|
NzInputModule,
|
|
19461
19503
|
NzGridModule,
|
|
19462
19504
|
NzFlexModule,
|
|
19463
|
-
ExtendInputNumber,
|
|
19464
19505
|
NzTableModule,
|
|
19465
19506
|
NzDividerModule,
|
|
19466
|
-
AutoFocusDirective,
|
|
19467
19507
|
NzAutocompleteModule,
|
|
19468
|
-
IconDelete,
|
|
19469
19508
|
NzModalComponent,
|
|
19470
19509
|
NzModalContentDirective,
|
|
19471
|
-
NzModalTitleDirective,
|
|
19472
|
-
IconAdd,
|
|
19473
|
-
NzModalFooterDirective,
|
|
19474
|
-
DicDomainSelectComponent$1,
|
|
19475
|
-
IconInfo,
|
|
19476
19510
|
WF_TemplateDetail,
|
|
19477
|
-
], selector: 'app-workflow-combine-editor', template: "<div\n #canvas\n class=\"workflow-canvas\"\n [class.connecting]=\"!!connectingFrom\"\n [class.dragging-point]=\"!!draggingPoint\"\n style=\"width: 100%; height: 100%\"\n (mousedown)=\"onMouseDownCanvas($event)\"\n (mousemove)=\"onMouseMoveCanvas($event)\"\n (mouseup)=\"onMouseUpCanvas($event)\"\n (click)=\"onClickCanvas($event)\"\n (wheel)=\"onWheelCanvas($event)\"\n>\n <!-- TOOLBAR -->\n <div class=\"toolbar\" (mousedown)=\"$event.stopPropagation()\" (click)=\"$event.stopPropagation()\">\n <button nz-button nzSize=\"small\" nz-tooltip=\"Editor setting\" (click)=\"settingVisible = true\">\n <nz-icon nzType=\"setting\"></nz-icon>\n </button>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Infomation\" (click)=\"infoVisible = true\">\n <nz-icon nzType=\"info-circle\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Global Setting\" (click)=\"drawTemplateVisibel = true\">\n <nz-icon nzType=\"setting\"></nz-icon> G\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nzDanger [nzLoading]=\"!ready\" nz-tooltip=\"Save (Ctrl + S)\" (click)=\"save()\">\n <nz-icon nzType=\"save\"></nz-icon>\n </button>\n <button nz-button nzSize=\"small\" nz-tooltip=\"Th\u00EAm Template m\u1EDBi\" (click)=\"isModalVisible = true\">\n <nz-icon nzType=\"plus\" class=\"color-primary\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Move mode\"\n (click)=\"isMoveMode = true\"\n >\n <nz-icon><img src=\"/assets/icon/hand-palm.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n [nzType]=\"!isMoveMode ? 'primary' : 'default'\"\n nz-tooltip=\"Select mode\"\n (click)=\"isMoveMode = false\"\n >\n <nz-icon><img src=\"/assets/icon/cursor.png\" width=\"19\" height=\"19\" /></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- UNDO / REDO -->\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"undoStack.length === 0\"\n nz-tooltip=\"Undo\"\n (click)=\"undo()\"\n >\n <nz-icon nzType=\"undo\"></nz-icon>\n </button>\n <button\n nz-button\n nzSize=\"small\"\n nzType=\"default\"\n [disabled]=\"redoStack.length === 0\"\n nz-tooltip=\"Redo\"\n (click)=\"redo()\"\n >\n <nz-icon nzType=\"redo\"></nz-icon>\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ALIGN -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignLeft()\">\u27F8</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignCenter()\">\u2261</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignRight()\">\u27F9</button>\n <span class=\"divider\"></span>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignTop()\">\u21D1</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignMiddle()\">\u2550</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 2\" (click)=\"alignBottom()\">\u21D3</button>\n <span class=\"divider\"></span>\n <!-- DISTRIBUTE -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 3\" (click)=\"distributeHorizontal()\">\n \u21C4\n </button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedTemplateId.size < 3\" (click)=\"distributeVertical()\">\n \u21C5\n </button>\n\n <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <!-- ZOOM -->\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"zoomOut()\" nz-tooltip=\"Zoom Out\">\n <nz-icon nzType=\"minus\"></nz-icon>\n </button>\n <span>{{ Math.round(zoom * 100) }}%</span>\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"zoomIn()\" nz-tooltip=\"Zoom In\">\n <nz-icon nzType=\"plus\"></nz-icon>\n </button>\n <span class=\"divider\"></span>\n <button nz-button nzSize=\"small\" nzType=\"default\" (click)=\"resetZoom()\" nz-tooltip=\"Reset Zoom (Ctrl+0)\">\n <nz-icon nzType=\"expand\"></nz-icon>\n </button>\n </div>\n\n <div\n class=\"canvas-content\"\n [class.panning]=\"isMoveMode\"\n [style.width.px]=\"getCanvasWidth()\"\n [style.height.px]=\"getCanvasHeight()\"\n [style.transform]=\"\n 'translate(' +\n templateCombine.editorOption.panX +\n 'px,' +\n templateCombine.editorOption.panY +\n 'px) scale(' +\n zoom +\n ')'\n \"\n >\n <!-- GRID -->\n <div *ngIf=\"wfcSetting.ShowGrid\" class=\"grid-layer\"></div>\n\n <!-- SVG EDGES -->\n <svg #svg class=\"edges-layer\" width=\"100%\" height=\"100%\" preserveAspectRatio=\"none\">\n <g>\n <!-- DEFS -->\n <defs>\n <filter id=\"edge-glow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n <feGaussianBlur stdDeviation=\"2\" result=\"blur\" />\n <feMerge>\n <feMergeNode in=\"blur\" />\n <feMergeNode in=\"SourceGraphic\" />\n </feMerge>\n </filter>\n\n <marker\n id=\"arrow-blue\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n <marker\n id=\"arrow-red\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n refX=\"10\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M0,0 L10,5 L0,10\"></path>\n </marker>\n </defs>\n\n <!-- EDGES B\u00CCNH TH\u01AF\u1EDCNG -->\n <ng-container *ngFor=\"let e of normalEdges; let i = index\">\n <path class=\"edge\" [attr.id]=\"'edge-path-' + i\" [attr.d]=\"buildPath(e)\" marker-end=\"url(#arrow-blue)\"></path>\n\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseenter)=\"onMouseEnterEdge(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <!-- \u0110\u00E3 x\u00F3a *ngIf=\"e.RuleLineDetails?.length\" \u1EDF \u0111\u00E2y \u0111\u1EC3 text lu\u00F4n hi\u1EC7n -->\n <text\n class=\"edge-label\"\n style=\"fill: #1890ff; font-weight: 500\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.FromStage }} > {{ e.FromAction }}\n </text>\n </ng-container>\n\n <!-- EDGE \u0110ANG HOVER/SELECTED (HI\u1EC2N TH\u1ECA M\u00C0U \u0110\u1ECE) -->\n <ng-container *ngFor=\"let e of hoverEdges; let i = index\">\n <path\n class=\"edge red\"\n [attr.id]=\"'edge-path-hover-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-red)\"\n ></path>\n\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\n <text\n class=\"edge-label\"\n style=\"font-weight: bold; fill: red\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.FromStage }} > {{ e.FromAction }}\n </text>\n </ng-container>\n\n <!-- PREVIEW LINE (\u0110\u01AF\u1EDCNG N\u1ED0I \u0110ANG K\u00C9O) -->\n <path\n *ngIf=\"connectingFrom\"\n class=\"edge\"\n [attr.d]=\"buildPreviewPath()\"\n stroke-dasharray=\"5,5\"\n marker-end=\"url(#arrow-blue)\"\n ></path>\n </g>\n </svg>\n\n <!-- BOX V\u00D9NG CH\u1ECCN MULTI -->\n <div\n *ngIf=\"isSelecting && selectStart && selectEnd\"\n class=\"selection-box\"\n [style.left.px]=\"Math.min(selectStart.x, selectEnd.x)\"\n [style.top.px]=\"Math.min(selectStart.y, selectEnd.y)\"\n [style.width.px]=\"Math.abs(selectEnd.x - selectStart.x)\"\n [style.height.px]=\"Math.abs(selectEnd.y - selectStart.y)\"\n ></div>\n\n <!-- NODE (TEMPLATE) L\u1EDAP HI\u1EC2N TH\u1ECA TR\u00CAN C\u00D9NG -->\n @for (n of lstTemplateNode; track n.WF_Template_Id) {\n <nz-card\n class=\"workflow-node\"\n [attr.data-id]=\"n.Code\"\n [class.selected]=\"\n n == selectedTemplateNode || n == hoverTemplateNode || lstSelectedTemplateId.has(n.WF_Template_Id)\n \"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n) || isDraggingFrom(n) || isSelectedNode(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickNode(n)\"\n >\n <div class=\"title\" style=\"color: #1890ff; display: flex; justify-content: space-between; align-items: center\">\n <span>{{ n.Code }}</span>\n <nz-icon nzType=\"layout\" nzTheme=\"outline\"></nz-icon>\n </div>\n <div\n style=\"\n font-size: 12px;\n line-height: 1.2;\n font-weight: 500;\n height: 28px;\n overflow: hidden;\n text-overflow: ellipsis;\n \"\n >\n {{ n.Name || \"Ch\u01B0a c\u00F3 t\u00EAn\" }}\n </div>\n <div style=\"font-size: 10px; color: gray; margin-top: 4px\">\n {{ n.DocType }}\n </div>\n\n <!-- CONNECTOR \u0110\u1EC2 K\u00C9O D\u00C2Y -->\n <div class=\"connector connector-right\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n <div class=\"connector connector-left\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n </nz-card>\n }\n\n <!-- C\u00C1C \u0110I\u1EC2M WAYPOINT \u0110\u1EC2 B\u1EBA CONG D\u00C2Y CHU\u1ED8T -->\n @for (p of connectingPoints; track $index) {\n @if (p != draggingPoint) {\n <div\n class=\"waypoint\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n (contextmenu)=\"onRightClickPoint($event, hoverTemplateEdge!, $index)\"\n ></div>\n } @else {\n <div\n class=\"waypoint dragging\"\n [style.left.px]=\"p.x\"\n [style.top.px]=\"p.y\"\n (mousedown)=\"onmousedownPoint($event, p)\"\n ></div>\n }\n }\n </div>\n</div>\n\n<!-- ==============================================\n 1. DRAWER: GLOBAL TEMPLATE SETTINGS \n=============================================== -->\n<nz-drawer\n [nzTitle]=\"drawTemplateTitle\"\n nzPlacement=\"right\"\n [nzWidth]=\"500\"\n [nzClosable]=\"false\"\n [nzVisible]=\"drawTemplateVisibel\"\n [nzFooter]=\"footerTplTemplate\"\n (nzOnClose)=\"drawTemplateVisibel = false\"\n>\n <ng-template #drawTemplateTitle> <nz-icon nzType=\"global\"></nz-icon> 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> 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> 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> 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> 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> H\u01B0\u1EDBng d\u1EABn (Infomation) </ng-template>\n <ng-container *nzDrawerContent>\n <p>\n <strong>1. C\u00E1c th\u00E0nh ph\u1EA7n:</strong> C\u00E1c \u00F4 ch\u1EEF nh\u1EADt l\u00E0 Template (Quy tr\u00ECnh nh\u1ECF), c\u00E1c \u0111\u01B0\u1EDDng n\u1ED1i l\u00E0 Transition Rule\n (Quy t\u1EAFc chuy\u1EC3n quy tr\u00ECnh).\n </p>\n <p><strong>2. C\u00E1ch n\u1ED1i 2 Template:</strong></p>\n <ul>\n <li>Click ch\u1EA5m cam b\u00EAn ph\u1EA3i Template A, sau \u0111\u00F3 k\u00E9o v\u00E0 click v\u00E0o Template B \u0111\u1EC3 t\u1EA1o Rule n\u1ED1i.</li>\n <li>C\u00F3 th\u1EC3 click nhi\u1EC1u \u0111i\u1EC3m trong l\u00FAc k\u00E9o \u0111\u1EC3 b\u1EBB \u0111\u01B0\u1EDDng cong tu\u1EF3 \u00FD (Waypoint).</li>\n <li>Click \u0111\u00FAp v\u00E0o c\u1EA1nh (\u0111\u01B0\u1EDDng n\u1ED1i) \u0111ang c\u00F3 \u0111\u1EC3 t\u1EA1o th\u00EAm m\u1ED9t \u0111i\u1EC3m b\u1EBB cong m\u1EDBi.</li>\n <li>Gi\u1EEF v\u00E0 k\u00E9o \u0111i\u1EC3m b\u1EBB cong \u0111\u1EC3 tu\u1EF3 ch\u1EC9nh \u0111\u01B0\u1EDDng \u0111i. Chu\u1ED9t ph\u1EA3i v\u00E0o \u0111i\u1EC3m \u0111\u00F3 \u0111\u1EC3 x\u00F3a n\u00F3.</li>\n </ul>\n <p>\n <strong>3. Qu\u1EA3n l\u00FD Rule:</strong> Click v\u00E0o \u0111\u01B0\u1EDDng n\u1ED1i gi\u1EEFa 2 Node \u0111\u1EC3 c\u1EA5u h\u00ECnh c\u00E1c lu\u1ED3ng th\u1EF1c thi (Stored, Ph\u00E2n\n quy\u1EC1n, G\u1EEDi mail).\n </p>\n </ng-container>\n</nz-drawer>\n\n<nz-modal\n [(nzVisible)]=\"isModalVisible\"\n nzTitle=\"Add template node\"\n [nzWidth]=\"600\"\n (nzOnCancel)=\"isModalVisible = false\"\n (nzOnOk)=\"addTemplateNodes()\"\n nzOkText=\"Add\"\n nzOkDanger\n nzCancelText=\"Cancel\"\n nzMaskClosable=\"false\"\n>\n <ng-container *nzModalContent>\n <extend-select\n label=\"Template\"\n [lstItem]=\"lstTemplateForSelect\"\n [displayField]=\"'Name'\"\n [multiple]=\"true\"\n [(_ngModel)]=\"lstTemplateSelected\"\n ></extend-select>\n </ng-container>\n</nz-modal>\n", styles: ["@charset \"UTF-8\";::ng-deep .workflow-wrapper{border:solid 1px lightgray;overflow:hidden;width:100%}.workflow-canvas{position:relative;background:#f0f2f5;cursor:default;overflow:hidden;outline:1px dashed rgba(0,0,0,.1)}.workflow-canvas .edges-layer{position:absolute;inset:0;width:100%;height:100%;z-index:1}.workflow-canvas .edges-layer path{stroke-width:2;fill:none}.canvas-content{transform-origin:0 0;width:100%;height:100%;transition:transform .05s linear}.canvas-content{outline:1px dashed red}.canvas-content.panning{cursor:grab}.canvas-content.panning:active{cursor:grabbing}.workflow-canvas.panning{cursor:grab}.workflow-canvas.panning:active{cursor:grabbing}.workflow-canvas.connecting,.workflow-canvas.connecting .workflow-node{cursor:crosshair}.workflow-node{position:absolute;width:160px;cursor:grab;-webkit-user-select:none;user-select:none;z-index:2}.workflow-node:active{cursor:grabbing}.workflow-node.connecting-source,.workflow-node.selected,.workflow-node:hover:not(.workflow-node-start,.workflow-node-end){outline:2px dashed #1890ff}.workflow-node .title{font-weight:600;margin-bottom:6px}.workflow-node-start{width:0px}.workflow-node-start.connecting-source,.workflow-node-start.selected,.workflow-node-start:hover{outline:unset}.workflow-node-start.connecting-source nz-tag,.workflow-node-start.selected nz-tag,.workflow-node-start:hover nz-tag{outline:2px dashed}.workflow-node-start nz-tag{position:relative;top:45px;right:35px}.workflow-node-end{width:0px}.workflow-node-end.connecting-source,.workflow-node-end.selected,.workflow-node-end:hover{outline:unset}.workflow-node-end.connecting-source nz-tag,.workflow-node-end.selected nz-tag,.workflow-node-end:hover nz-tag{outline:2px dashed}.workflow-node-end nz-tag{position:relative;top:45px;right:32px}.connector{position:absolute;top:39px;width:12px;height:12px;background:#1890ff;border-radius:50%;transform:translateY(-50%);cursor:crosshair;transition:box-shadow .15s ease-out,transform .15s ease-out}.connector:hover{box-shadow:0 0 0 3px #1890ff4d;transform:translateY(-50%) scale(1.15)}.connector-right{right:-8px;background:orange}.connector-right.reverse,.connector-left{left:-8px}.connector-left.reverse{left:unset;right:-8px}.connector-start{width:16px;height:16px;right:-8px;background:green;box-shadow:0 0 0 3px #1890ff4d}.connector-end{width:16px;height:16px;left:-8px;background:#000;box-shadow:0 0 0 3px #1890ff4d}.edge{cursor:pointer;stroke:#1890ff;stroke-linecap:round;stroke-linejoin:round;stroke-width:2;fill:none;transition:stroke .15s ease}.edge-hit{stroke:transparent;stroke-width:18px!important;fill:none;cursor:pointer}.edge-hit:hover+.edge{stroke:#ff4d4f;stroke-width:2}.workflow-canvas.dragging-point .edge-hit{pointer-events:none}.edge:hover+.edge-label{fill:#1890ff;font-weight:500}.edge-label{font-size:12px;fill:#555;pointer-events:none;-webkit-user-select:none;user-select:none}.blue{stroke:#1890ff!important}.red{stroke:#ff4d4f!important;box-shadow:0 0 0 3px #1890ff4d!important}.workflow-svg{background:transparent;overflow:visible}.waypoint{position:absolute;width:10px;height:10px;background:#ff4d4f;border-radius:50%;transform:translate(-50%,-50%) scale(1);cursor:move;z-index:1;transition:transform .12s ease-out,background-color .12s ease-out,box-shadow .12s ease-out}.waypoint:hover{background:#ff7875;transform:translate(-50%,-50%) scale(1.25);box-shadow:0 0 0 4px #ff787559}.waypoint.dragging{transition:none;transform:translate(-50%,-50%) scale(1.15);pointer-events:none}.workflow-canvas.dragging-point svg{cursor:grabbing}.selection-box{position:absolute;border:1px dashed #1890ff;background:#1890ff1a;pointer-events:none}.toolbar{position:absolute;top:8px;left:8px;display:flex;gap:4px;padding:6px;background:#fff;border-radius:6px;box-shadow:0 2px 8px #00000026;z-index:100}.toolbar .divider{width:1px;background:#e5e5e5;margin:0 2px}nz-tag.selected{outline:2px dashed #1890ff}.grid-layer{position:absolute;inset:0;pointer-events:none;z-index:0;background-image:radial-gradient(rgba(0,0,0,.08) 1px,transparent 1px);background-size:20px 20px}.grid-layer{background-image:linear-gradient(to right,rgba(0,0,0,.06) 1px,transparent 1px),linear-gradient(to bottom,rgba(0,0,0,.06) 1px,transparent 1px);background-size:20px 20px}.editable-tag{background:#fff;border-style:dashed}::ng-deep .minimap,.minimap-combine{position:absolute;width:180px;height:125px;top:0;right:0;background-color:#eee;border:1px solid #aaa;opacity:.9;z-index:1}::ng-deep .minimap{position:absolute;width:200px;height:140px;top:8px;right:8px;background-color:#f8f9fa;border:1px solid #d9d9d9;border-radius:8px;box-shadow:0 4px 12px #0000001a;overflow:hidden;z-index:100;-webkit-user-select:none;user-select:none}::ng-deep .minimap-node{position:absolute;background-color:#bfbfbf;border-radius:2px}::ng-deep .minimap-node-round{position:absolute;background-color:#bfbfbf;border-radius:50%}::ng-deep .minimap-node-round-start{background-color:#52c41a}::ng-deep .minimap-node-round-end{background-color:#ff4d4f}::ng-deep .minimap-viewport{position:absolute;box-sizing:border-box;background-color:#1890ff26;border:1.5px solid #1890ff;border-radius:4px;z-index:2;cursor:grab;transition:none}::ng-deep .minimap-viewport.grabbing,::ng-deep .minimap-viewport:active{cursor:grabbing;background-color:#1890ff40}::ng-deep .has-floating-label.floating-label{position:relative;padding-top:14px}::ng-deep .has-floating-label nz-form-item nz-form-label{position:absolute;top:12px;left:13px;transform:translateY(-50%);background:linear-gradient(to bottom,var(--form-bg-color, #ffffff) 80%,#ffffff 80%);z-index:1;height:auto;line-height:normal;padding:0 4px}::ng-deep .has-floating-label nz-form-item nz-form-label label{font-size:12px;color:var(--darkgray, #565656);font-weight:700;height:auto;line-height:normal;padding:0;display:flex;align-items:center}::ng-deep .has-floating-label .full-width{width:100%}.has-floating-label.floating-label nz-form-item:has(.ant-select-disabled) nz-form-label,.has-floating-label.floating-label nz-form-item:has(input[disabled]) nz-form-label,.has-floating-label.floating-label nz-form-item:has(.ant-input-disabled) nz-form-label{background:linear-gradient(to bottom,var(--form-bg-color, #ffffff) 60%,#f5f5f5 50%)}.has-floating-label.floating-label nz-form-item:has(.ant-select-disabled) nz-form-label label,.has-floating-label.floating-label nz-form-item:has(input[disabled]) nz-form-label label,.has-floating-label.floating-label nz-form-item:has(.ant-input-disabled) nz-form-label label{color:#bfbfbf}\n"] }]
|
|
19478
19512
|
}], propDecorators: { lstTemplateForSelect: [{
|
|
19479
19513
|
type: Input
|
|
19514
|
+
}], getdata: [{
|
|
19515
|
+
type: Output
|
|
19480
19516
|
}], onSave: [{
|
|
19481
|
-
type: Output
|
|
19482
|
-
args: ['onSave']
|
|
19517
|
+
type: Output
|
|
19483
19518
|
}], onDeleteTempldateNode: [{
|
|
19484
|
-
type: Output
|
|
19485
|
-
args: ['onDeleteTempldateNode']
|
|
19519
|
+
type: Output
|
|
19486
19520
|
}], canvasRef: [{
|
|
19487
19521
|
type: ViewChild,
|
|
19488
19522
|
args: ['canvas', { static: true }]
|
|
@@ -19504,10 +19538,12 @@ class WF_Template_CombineDetailComponent extends BaseComponent {
|
|
|
19504
19538
|
wfeditor;
|
|
19505
19539
|
ngOnInit() {
|
|
19506
19540
|
this.updateBC();
|
|
19507
|
-
|
|
19508
|
-
this.getData(id);
|
|
19541
|
+
this.getData();
|
|
19509
19542
|
}
|
|
19510
19543
|
getData(id) {
|
|
19544
|
+
id = id || this.getUrlParam('id');
|
|
19545
|
+
if (!id)
|
|
19546
|
+
return;
|
|
19511
19547
|
this.service.getLstTemplate().then((res) => (this.lstTemplate = res.Data));
|
|
19512
19548
|
this.service.getWFCombine(id).then((res) => {
|
|
19513
19549
|
this.templateCombine = new WFTemplate_Combine(res.Data);
|
|
@@ -19552,11 +19588,11 @@ class WF_Template_CombineDetailComponent extends BaseComponent {
|
|
|
19552
19588
|
});
|
|
19553
19589
|
}
|
|
19554
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 });
|
|
19555
|
-
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
|
|
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"] }] });
|
|
19556
19592
|
}
|
|
19557
19593
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WF_Template_CombineDetailComponent, decorators: [{
|
|
19558
19594
|
type: Component,
|
|
19559
|
-
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
|
|
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"] }]
|
|
19560
19596
|
}], propDecorators: { wfeditor: [{
|
|
19561
19597
|
type: ViewChild,
|
|
19562
19598
|
args: ['wfeditor']
|