@brggroup/share-lib 0.0.39 → 0.0.41
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.
|
@@ -2748,15 +2748,15 @@ class WF_TemplateStage {
|
|
|
2748
2748
|
Name;
|
|
2749
2749
|
StageType;
|
|
2750
2750
|
SeqValue;
|
|
2751
|
+
NumberDay;
|
|
2751
2752
|
LimitValue;
|
|
2752
2753
|
IsRequireUser;
|
|
2753
2754
|
// #endregion properties
|
|
2754
|
-
|
|
2755
|
+
IsTempId;
|
|
2755
2756
|
constructor(obj) {
|
|
2756
2757
|
obj = obj || {};
|
|
2757
2758
|
this.WF_TemplateStage_Id = obj.WF_TemplateStage_Id || null;
|
|
2758
2759
|
this.App_Org_Id = obj.App_Org_Id || '';
|
|
2759
|
-
this.OrgImplCode = obj.OrgImplCode || '';
|
|
2760
2760
|
this.CreatedDate = obj.CreatedDate || null;
|
|
2761
2761
|
this.CreatedUser = obj.CreatedUser || '';
|
|
2762
2762
|
this.UpdatedDate = obj.UpdatedDate || null;
|
|
@@ -2767,8 +2767,10 @@ class WF_TemplateStage {
|
|
|
2767
2767
|
this.Name = obj.Name || '';
|
|
2768
2768
|
this.StageType = obj.StageType || '';
|
|
2769
2769
|
this.SeqValue = obj.SeqValue || null;
|
|
2770
|
+
this.NumberDay = obj.NumberDay || null;
|
|
2770
2771
|
this.LimitValue = obj.LimitValue || null;
|
|
2771
|
-
this.IsRequireUser = obj.IsRequireUser ||
|
|
2772
|
+
this.IsRequireUser = obj.IsRequireUser || false;
|
|
2773
|
+
this.IsTempId = obj.IsTempId || false;
|
|
2772
2774
|
}
|
|
2773
2775
|
}
|
|
2774
2776
|
class WF_TemplateStageAction {
|
|
@@ -2793,6 +2795,10 @@ class WF_TemplateStageAction {
|
|
|
2793
2795
|
To_StageStatus;
|
|
2794
2796
|
WF_TransitionsRule_Id;
|
|
2795
2797
|
// #endregion properties
|
|
2798
|
+
lstRoleId;
|
|
2799
|
+
_lstRoleId;
|
|
2800
|
+
lstEmailActionId;
|
|
2801
|
+
_lstEmailActionId;
|
|
2796
2802
|
constructor(obj) {
|
|
2797
2803
|
obj = obj || {};
|
|
2798
2804
|
this.WF_TemplateStageAction_Id = obj.WF_TemplateStageAction_Id || null;
|
|
@@ -2814,61 +2820,129 @@ class WF_TemplateStageAction {
|
|
|
2814
2820
|
this.To_WF_TemplateStage_Id = obj.To_WF_TemplateStage_Id || null;
|
|
2815
2821
|
this.To_StageStatus = obj.To_StageStatus || '';
|
|
2816
2822
|
this.WF_TransitionsRule_Id = obj.WF_TransitionsRule_Id || null;
|
|
2823
|
+
this.lstRoleId = obj.lstRoleId;
|
|
2824
|
+
this._lstRoleId = this.lstRoleId ? this.lstRoleId.split(',') : [];
|
|
2825
|
+
this.lstEmailActionId = obj.lstEmailActionId;
|
|
2826
|
+
this._lstEmailActionId = this.lstEmailActionId
|
|
2827
|
+
? this.lstEmailActionId
|
|
2828
|
+
.split(',')
|
|
2829
|
+
.map((x) => Number(x.trim()))
|
|
2830
|
+
.filter((x) => !isNaN(x))
|
|
2831
|
+
: [];
|
|
2817
2832
|
}
|
|
2818
2833
|
}
|
|
2819
2834
|
class Workflow extends WF_Template {
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2835
|
+
lstTemplateType;
|
|
2836
|
+
lstTemplatePrint;
|
|
2837
|
+
lstStageStatus;
|
|
2838
|
+
lstActionType;
|
|
2839
|
+
lstActionStatus;
|
|
2840
|
+
constructor(obj) {
|
|
2841
|
+
obj = obj || {};
|
|
2842
|
+
super(obj);
|
|
2843
|
+
this.lstTemplateType = obj.lstTemplateType || [];
|
|
2844
|
+
this.lstTemplatePrint = obj.lstTemplatePrint || [];
|
|
2845
|
+
this.lstStageStatus = obj.lstStageStatus || [];
|
|
2846
|
+
this.lstActionType = obj.lstActionType || [];
|
|
2847
|
+
this.lstActionStatus = obj.lstActionStatus || [];
|
|
2848
|
+
}
|
|
2823
2849
|
}
|
|
2824
2850
|
/**
|
|
2825
2851
|
* STAGE
|
|
2826
2852
|
*/
|
|
2827
2853
|
class WorkflowStage extends WF_TemplateStage {
|
|
2828
|
-
|
|
2829
|
-
|
|
2854
|
+
lstAction;
|
|
2855
|
+
editorOption = new WorkflowStageEditorOption();
|
|
2856
|
+
constructor(obj) {
|
|
2857
|
+
obj = obj || {};
|
|
2858
|
+
super(obj);
|
|
2859
|
+
this.lstAction = [];
|
|
2860
|
+
if (obj.lstAction) {
|
|
2861
|
+
obj.lstAction.forEach((x) => {
|
|
2862
|
+
this.lstAction = [...this.lstAction, new WorkflowAction(x)];
|
|
2863
|
+
});
|
|
2864
|
+
}
|
|
2865
|
+
this.editorOption = obj.editorOption || new WorkflowStageEditorOption();
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2868
|
+
class WorkflowStageEditorOption {
|
|
2869
|
+
x;
|
|
2870
|
+
y;
|
|
2830
2871
|
isReverse;
|
|
2831
2872
|
isReverseLabel;
|
|
2832
|
-
lstAction;
|
|
2833
2873
|
drawerPosition;
|
|
2834
2874
|
constructor(obj) {
|
|
2835
2875
|
obj = obj || {};
|
|
2836
|
-
|
|
2837
|
-
this.
|
|
2838
|
-
this.
|
|
2839
|
-
this.
|
|
2840
|
-
this.
|
|
2841
|
-
this.lstAction = obj.lstAction;
|
|
2842
|
-
this.drawerPosition = obj.drawerPosition;
|
|
2876
|
+
this.x = obj.x || 0;
|
|
2877
|
+
this.y = obj.y || 0;
|
|
2878
|
+
this.isReverse = obj.isReverse || false;
|
|
2879
|
+
this.isReverseLabel = obj.isReverseLabel || false;
|
|
2880
|
+
this.drawerPosition = obj.drawerPosition || '';
|
|
2843
2881
|
}
|
|
2844
2882
|
}
|
|
2845
2883
|
/**
|
|
2846
2884
|
* Action
|
|
2847
2885
|
*/
|
|
2848
2886
|
class WorkflowAction extends WF_TemplateStageAction {
|
|
2887
|
+
FromStageCode;
|
|
2888
|
+
FromStageName;
|
|
2889
|
+
ToStageCode;
|
|
2849
2890
|
NextStageStatus; // string
|
|
2850
|
-
FromStage;
|
|
2851
2891
|
FromSide;
|
|
2852
|
-
ToStage;
|
|
2853
2892
|
ToSide;
|
|
2854
2893
|
allowBack; // true = 2 đầu, false/undefined = 1 đầu
|
|
2855
2894
|
labelBack;
|
|
2856
|
-
points;
|
|
2857
2895
|
isBackAction;
|
|
2896
|
+
editorOption;
|
|
2897
|
+
constructor(obj) {
|
|
2898
|
+
obj = obj || {};
|
|
2899
|
+
super(obj);
|
|
2900
|
+
this.FromStageCode = obj.FromStageCode || '';
|
|
2901
|
+
this.FromStageName = obj.FromStageName || '';
|
|
2902
|
+
this.NextStageStatus = obj.NextStageStatus || '';
|
|
2903
|
+
this.ToStageCode = obj.ToStageCode || '';
|
|
2904
|
+
this.FromSide = obj.FromSide || '';
|
|
2905
|
+
this.ToSide = obj.ToSide || '';
|
|
2906
|
+
this.allowBack = obj.allowBack || false;
|
|
2907
|
+
this.labelBack = obj.labelBack || '';
|
|
2908
|
+
this.isBackAction = obj.isBackAction || false;
|
|
2909
|
+
this.editorOption = new WorkflowActionEditorOption(obj.editorOption);
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
class WorkflowActionEditorOption {
|
|
2913
|
+
points;
|
|
2858
2914
|
drawerPosition;
|
|
2915
|
+
constructor(obj) {
|
|
2916
|
+
obj = obj || {};
|
|
2917
|
+
this.drawerPosition = obj.drawerPosition || '';
|
|
2918
|
+
this.points = [];
|
|
2919
|
+
if (obj.points) {
|
|
2920
|
+
obj.points.forEach((p) => {
|
|
2921
|
+
this.points = [...this.points, { x: p.x, y: p.y }];
|
|
2922
|
+
});
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2859
2925
|
}
|
|
2860
2926
|
class WorkflowEditorComponent extends BaseComponent {
|
|
2861
2927
|
//#region NGHIỆP VỤ
|
|
2862
2928
|
lstOrg = [];
|
|
2863
|
-
|
|
2864
|
-
lstTemplatePrint = [];
|
|
2929
|
+
lstRole = [];
|
|
2865
2930
|
template = new Workflow();
|
|
2866
|
-
lstStage = [
|
|
2867
|
-
new WorkflowStage({ Code: 'start', Name: 'Start', x: -35, y: 120, StageType: 'START', SeqValue: 1 }),
|
|
2868
|
-
new WorkflowStage({ Code: 'end', Name: 'End', x: 780, y: 120, StageType: 'END', SeqValue: 999 }),
|
|
2869
|
-
];
|
|
2931
|
+
lstStage = [];
|
|
2870
2932
|
lstAction = [];
|
|
2933
|
+
get lstEmailAction() {
|
|
2934
|
+
if (this.lstAction && this.lstAction.length) {
|
|
2935
|
+
const res = this.lstAction.map((x) => ({
|
|
2936
|
+
ID: x.WF_TemplateStageAction_Id,
|
|
2937
|
+
Name: `${x.FromStageCode}${x.FromStageName ? ' - ' : ''}${x.FromStageName} / ${x.ActionStatus}${x.ActionText ? ' - ' : ''}${x.ActionText}`,
|
|
2938
|
+
}));
|
|
2939
|
+
return res;
|
|
2940
|
+
}
|
|
2941
|
+
return [];
|
|
2942
|
+
}
|
|
2871
2943
|
onSave = new EventEmitter();
|
|
2944
|
+
onDeleteStage = new EventEmitter();
|
|
2945
|
+
onDeleteAction = new EventEmitter();
|
|
2872
2946
|
//#endregion
|
|
2873
2947
|
Math = Math;
|
|
2874
2948
|
drawTemplateVisibel = false;
|
|
@@ -2897,7 +2971,7 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
2897
2971
|
dragStartPositions = new Map();
|
|
2898
2972
|
dragStartEdgePoints = new Map();
|
|
2899
2973
|
/** list các điểm đang được chọn */
|
|
2900
|
-
|
|
2974
|
+
lstSelectedStageId = new Set();
|
|
2901
2975
|
// SNAP point
|
|
2902
2976
|
gridSize = 20; // 10 / 20 / 25 tuỳ thích
|
|
2903
2977
|
snapToGrid = true;
|
|
@@ -2975,45 +3049,75 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
2975
3049
|
this.moveSelectedNodesBy(dx, dy);
|
|
2976
3050
|
}
|
|
2977
3051
|
}
|
|
2978
|
-
ngOnInit() {
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
3052
|
+
ngOnInit() { }
|
|
3053
|
+
ngAfterViewInit() {
|
|
3054
|
+
this.updateCanvasSize();
|
|
3055
|
+
}
|
|
3056
|
+
afterInput() {
|
|
3057
|
+
this.template = this.template ? new Workflow(this.template) : new Workflow();
|
|
2983
3058
|
if (!this.lstStage || !this.lstStage.length) {
|
|
2984
3059
|
this.lstStage = [
|
|
2985
|
-
{
|
|
2986
|
-
|
|
3060
|
+
new WorkflowStage({
|
|
3061
|
+
Code: 'start',
|
|
3062
|
+
Name: 'Start',
|
|
3063
|
+
StageType: 'START',
|
|
3064
|
+
SeqValue: 1,
|
|
3065
|
+
editorOption: {
|
|
3066
|
+
x: 5000 + -35,
|
|
3067
|
+
y: 5000 + 120,
|
|
3068
|
+
},
|
|
3069
|
+
}),
|
|
3070
|
+
new WorkflowStage({
|
|
2987
3071
|
Code: 'end',
|
|
2988
3072
|
Name: 'End',
|
|
2989
|
-
x: 5000 + 120,
|
|
2990
|
-
y: 5000 + 380,
|
|
2991
3073
|
StageType: 'END',
|
|
2992
|
-
isReverseLabel: true,
|
|
2993
3074
|
SeqValue: 999,
|
|
2994
|
-
|
|
3075
|
+
editorOption: {
|
|
3076
|
+
x: 5000 + 120,
|
|
3077
|
+
y: 5000 + 300,
|
|
3078
|
+
isReverseLabel: true,
|
|
3079
|
+
},
|
|
3080
|
+
}),
|
|
2995
3081
|
];
|
|
2996
3082
|
}
|
|
3083
|
+
else {
|
|
3084
|
+
let lstStage = [];
|
|
3085
|
+
this.lstStage.forEach((x) => {
|
|
3086
|
+
lstStage = [...lstStage, new WorkflowStage(x)];
|
|
3087
|
+
});
|
|
3088
|
+
this.lstStage = lstStage;
|
|
3089
|
+
}
|
|
3090
|
+
if (!this.lstAction || !this.lstAction.length) {
|
|
3091
|
+
this.lstAction = [];
|
|
3092
|
+
}
|
|
3093
|
+
else {
|
|
3094
|
+
let lstAction = [];
|
|
3095
|
+
this.lstAction.forEach((x) => {
|
|
3096
|
+
lstAction = [...lstAction, new WorkflowAction(x)];
|
|
3097
|
+
});
|
|
3098
|
+
this.lstAction = lstAction;
|
|
3099
|
+
}
|
|
2997
3100
|
this.lstStage.forEach((x) => {
|
|
2998
|
-
x.lstAction = this.lstAction.filter((y) => y.
|
|
3101
|
+
x.lstAction = this.lstAction.filter((y) => y.WF_TemplateStage_Id == x.WF_TemplateStage_Id);
|
|
2999
3102
|
});
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
this.
|
|
3103
|
+
console.log('WorkflowEditorComponent ngOnInit');
|
|
3104
|
+
console.log('template', this.template);
|
|
3105
|
+
console.log('lstStage', this.lstStage);
|
|
3106
|
+
console.log('lstAction', this.lstAction);
|
|
3003
3107
|
}
|
|
3004
3108
|
moveSelectedNodesBy(dx, dy) {
|
|
3005
|
-
if (this.
|
|
3109
|
+
if (this.lstSelectedStageId.size === 0)
|
|
3006
3110
|
return;
|
|
3007
3111
|
// ⭐ UNDO SNAPSHOT
|
|
3008
3112
|
this.pushUndo({
|
|
3009
3113
|
type: 'move-nodes',
|
|
3010
|
-
before: this.cloneNodePositions(this.
|
|
3114
|
+
before: this.cloneNodePositions(this.lstSelectedStageId),
|
|
3011
3115
|
});
|
|
3012
3116
|
for (const n of this.lstStage) {
|
|
3013
|
-
if (!this.
|
|
3117
|
+
if (!this.lstSelectedStageId.has(n.WF_TemplateStage_Id))
|
|
3014
3118
|
continue;
|
|
3015
|
-
n.x = this.clamp(n.x + dx, 0, this.CANVAS_WIDTH - this.NODE_WIDTH);
|
|
3016
|
-
n.y = this.clamp(n.y + dy, 0, this.CANVAS_HEIGHT - this.NODE_HEIGHT);
|
|
3119
|
+
n.editorOption.x = this.clamp(n.editorOption.x + dx, 0, this.CANVAS_WIDTH - this.NODE_WIDTH);
|
|
3120
|
+
n.editorOption.y = this.clamp(n.editorOption.y + dy, 0, this.CANVAS_HEIGHT - this.NODE_HEIGHT);
|
|
3017
3121
|
}
|
|
3018
3122
|
}
|
|
3019
3123
|
save() {
|
|
@@ -3021,7 +3125,8 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3021
3125
|
}
|
|
3022
3126
|
addStage() {
|
|
3023
3127
|
console.log('addStage');
|
|
3024
|
-
const
|
|
3128
|
+
const id = Date.now();
|
|
3129
|
+
const code = 'New_Stage';
|
|
3025
3130
|
// tìm vị trí trống (đơn giản & hiệu quả)
|
|
3026
3131
|
const baseX = 200 - this.panX;
|
|
3027
3132
|
const baseY = 120 - this.panY;
|
|
@@ -3033,10 +3138,12 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3033
3138
|
y += GAP_Y;
|
|
3034
3139
|
}
|
|
3035
3140
|
const stage = new WorkflowStage();
|
|
3141
|
+
stage.WF_TemplateStage_Id = id;
|
|
3142
|
+
stage.IsTempId = true;
|
|
3036
3143
|
stage.Code = code;
|
|
3037
3144
|
stage.Name = 'New Stage';
|
|
3038
|
-
stage.x = x;
|
|
3039
|
-
stage.y = y;
|
|
3145
|
+
stage.editorOption.x = x;
|
|
3146
|
+
stage.editorOption.y = y;
|
|
3040
3147
|
stage.StageType = 'NODE';
|
|
3041
3148
|
stage.SeqValue = 10;
|
|
3042
3149
|
this.lstStage.push(stage);
|
|
@@ -3045,13 +3152,13 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3045
3152
|
this.hoverStage = stage;
|
|
3046
3153
|
}
|
|
3047
3154
|
isConnectingFrom(node) {
|
|
3048
|
-
return this.connectingFrom?.node.
|
|
3155
|
+
return this.connectingFrom?.node.WF_TemplateStage_Id === node.WF_TemplateStage_Id;
|
|
3049
3156
|
}
|
|
3050
3157
|
isDraggingFrom(node) {
|
|
3051
|
-
return this.draggingNode?.
|
|
3158
|
+
return this.draggingNode?.WF_TemplateStage_Id === node.WF_TemplateStage_Id;
|
|
3052
3159
|
}
|
|
3053
3160
|
isSelectedNode(node) {
|
|
3054
|
-
return this.selectedStage?.
|
|
3161
|
+
return this.selectedStage?.WF_TemplateStage_Id === node.WF_TemplateStage_Id;
|
|
3055
3162
|
}
|
|
3056
3163
|
cancelConnecting() {
|
|
3057
3164
|
if (this.connectingFrom) {
|
|
@@ -3062,27 +3169,32 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3062
3169
|
}
|
|
3063
3170
|
}
|
|
3064
3171
|
//#region NGHIỆP VỤ
|
|
3172
|
+
onselectedRoleEmail(action) {
|
|
3173
|
+
action.lstRoleId = action._lstRoleId ? action._lstRoleId.join(',') : '';
|
|
3174
|
+
action.lstEmailActionId = action._lstEmailActionId ? action._lstEmailActionId.join(',') : '';
|
|
3175
|
+
console.log('onselectedRoleEmail', action);
|
|
3176
|
+
}
|
|
3065
3177
|
addAction() {
|
|
3066
3178
|
if (!this.selectedStage)
|
|
3067
3179
|
return;
|
|
3068
3180
|
const action = new WorkflowAction();
|
|
3069
|
-
action.
|
|
3181
|
+
action.WF_TemplateStage_Id = this.selectedStage.WF_TemplateStage_Id;
|
|
3070
3182
|
action.FromSide = 'right';
|
|
3071
3183
|
this.selectedStage.lstAction = this.selectedStage.lstAction ? [...this.selectedStage.lstAction, action] : [action];
|
|
3072
3184
|
this.lstAction = this.lstAction ? [...this.lstAction, action] : [action];
|
|
3073
3185
|
}
|
|
3074
3186
|
onchangeAllowBack(action) {
|
|
3075
3187
|
console.log('onchangeAllowBack', action);
|
|
3076
|
-
const stage = this.lstStage.find((x) => x.
|
|
3188
|
+
const stage = this.lstStage.find((x) => x.WF_TemplateStage_Id == action.To_WF_TemplateStage_Id);
|
|
3077
3189
|
if (!stage) {
|
|
3078
3190
|
this.notiService.error('Stage not found');
|
|
3079
3191
|
return;
|
|
3080
3192
|
}
|
|
3081
3193
|
if (action.allowBack) {
|
|
3082
3194
|
const newAction = new WorkflowAction();
|
|
3083
|
-
newAction.
|
|
3195
|
+
newAction.WF_TemplateStage_Id = action.To_WF_TemplateStage_Id;
|
|
3084
3196
|
newAction.FromSide = 'right';
|
|
3085
|
-
newAction.
|
|
3197
|
+
newAction.To_WF_TemplateStage_Id = action.WF_TemplateStage_Id;
|
|
3086
3198
|
newAction.ToSide = 'left';
|
|
3087
3199
|
newAction.isBackAction = true;
|
|
3088
3200
|
console.log('newAction', newAction);
|
|
@@ -3092,7 +3204,9 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3092
3204
|
}
|
|
3093
3205
|
else {
|
|
3094
3206
|
action.labelBack = '';
|
|
3095
|
-
const backAction = this.lstAction.find((x) => x.
|
|
3207
|
+
const backAction = this.lstAction.find((x) => x.WF_TemplateStage_Id == action.To_WF_TemplateStage_Id &&
|
|
3208
|
+
x.To_WF_TemplateStage_Id == action.WF_TemplateStage_Id &&
|
|
3209
|
+
x.isBackAction);
|
|
3096
3210
|
console.log('remove action', backAction);
|
|
3097
3211
|
if (!backAction) {
|
|
3098
3212
|
this.notiService.error('Action not found');
|
|
@@ -3105,7 +3219,9 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3105
3219
|
}
|
|
3106
3220
|
}
|
|
3107
3221
|
onchangeLabelBack(action) {
|
|
3108
|
-
const backAction = this.lstAction.find((x) => x.
|
|
3222
|
+
const backAction = this.lstAction.find((x) => x.WF_TemplateStage_Id == action.To_WF_TemplateStage_Id &&
|
|
3223
|
+
x.To_WF_TemplateStage_Id == action.WF_TemplateStage_Id &&
|
|
3224
|
+
x.isBackAction);
|
|
3109
3225
|
if (!backAction) {
|
|
3110
3226
|
this.notiService.error('Action not found');
|
|
3111
3227
|
}
|
|
@@ -3115,7 +3231,9 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3115
3231
|
}
|
|
3116
3232
|
onchangeActionText(action) {
|
|
3117
3233
|
if (action.isBackAction) {
|
|
3118
|
-
const goAction = this.lstAction.find((x) => x.
|
|
3234
|
+
const goAction = this.lstAction.find((x) => x.WF_TemplateStage_Id == action.To_WF_TemplateStage_Id &&
|
|
3235
|
+
x.To_WF_TemplateStage_Id == action.WF_TemplateStage_Id &&
|
|
3236
|
+
!x.isBackAction);
|
|
3119
3237
|
if (!goAction) {
|
|
3120
3238
|
this.notiService.error('Action not found');
|
|
3121
3239
|
}
|
|
@@ -3127,37 +3245,42 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3127
3245
|
onchangeNextStage(action) {
|
|
3128
3246
|
console.log('onchangeNextStage', action);
|
|
3129
3247
|
}
|
|
3130
|
-
async
|
|
3248
|
+
async deleteStage() {
|
|
3249
|
+
console.log('deleteStage', this.selectedStage);
|
|
3131
3250
|
if (!this.selectedStage)
|
|
3132
3251
|
return;
|
|
3133
|
-
if (!(await this.confirm(`Xoá
|
|
3252
|
+
if (!(await this.confirm(`Xoá stage?`, `${this.selectedStage.Code} - ${this.selectedStage.Name}`)))
|
|
3134
3253
|
return;
|
|
3135
3254
|
const node = this.selectedStage;
|
|
3136
3255
|
// 🔹 snapshot edges liên quan
|
|
3137
|
-
const relatedEdges = this.lstAction.filter((e) => e.
|
|
3256
|
+
const relatedEdges = this.lstAction.filter((e) => e.WF_TemplateStage_Id === node.WF_TemplateStage_Id || e.To_WF_TemplateStage_Id === node.WF_TemplateStage_Id);
|
|
3138
3257
|
// 🔹 snapshot vị trí node trong mảng
|
|
3139
|
-
const nodeIndex = this.lstStage.findIndex((n) => n.
|
|
3140
|
-
//
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
})
|
|
3258
|
+
const nodeIndex = this.lstStage.findIndex((n) => n.WF_TemplateStage_Id === node.WF_TemplateStage_Id);
|
|
3259
|
+
// bỏ undo khi xóa node vì bắn event ra ngoài để xóa db
|
|
3260
|
+
// // ⭐ PUSH UNDO
|
|
3261
|
+
// this.pushUndo({
|
|
3262
|
+
// type: 'delete-node',
|
|
3263
|
+
// node: { ...node }, // clone
|
|
3264
|
+
// nodeIndex,
|
|
3265
|
+
// edges: relatedEdges.map((e) => ({ ...e })),
|
|
3266
|
+
// });
|
|
3147
3267
|
// ❌ xoá edges
|
|
3148
|
-
this.lstAction = this.lstAction.filter((e) => e.
|
|
3268
|
+
this.lstAction = this.lstAction.filter((e) => e.WF_TemplateStage_Id !== node.WF_TemplateStage_Id && e.To_WF_TemplateStage_Id !== node.WF_TemplateStage_Id);
|
|
3149
3269
|
// ❌ xoá node
|
|
3150
3270
|
this.lstStage.splice(nodeIndex, 1);
|
|
3271
|
+
this.onDeleteStage.emit(node);
|
|
3151
3272
|
this.selectedStage = undefined;
|
|
3152
3273
|
}
|
|
3153
3274
|
async deleteAction(action) {
|
|
3275
|
+
console.log('deleteAction', action);
|
|
3154
3276
|
if (!(await this.confirm(`Delete action ???`)))
|
|
3155
3277
|
return;
|
|
3156
|
-
const stage = this.lstStage.find((x) => x.
|
|
3278
|
+
const stage = this.lstStage.find((x) => x.WF_TemplateStage_Id == action.WF_TemplateStage_Id);
|
|
3157
3279
|
if (!stage)
|
|
3158
3280
|
return;
|
|
3159
3281
|
stage.lstAction = stage.lstAction?.filter((x) => x != action);
|
|
3160
3282
|
this.lstAction = this.lstAction.filter((x) => x != action);
|
|
3283
|
+
this.onDeleteAction.emit(action);
|
|
3161
3284
|
this.selectedAction = undefined;
|
|
3162
3285
|
this.hoverAction = undefined;
|
|
3163
3286
|
}
|
|
@@ -3231,6 +3354,21 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3231
3354
|
this.inputActionTypeVisible = false;
|
|
3232
3355
|
}
|
|
3233
3356
|
//#endregion
|
|
3357
|
+
//#region Action role
|
|
3358
|
+
inputActionRoleValue = '';
|
|
3359
|
+
handleCloseActionRole(removedTag) {
|
|
3360
|
+
this.template.lstActionStatus = this.template.lstActionStatus.filter((tag) => tag !== removedTag);
|
|
3361
|
+
}
|
|
3362
|
+
handleInputConfirmActionRole() {
|
|
3363
|
+
if (this.inputActionRoleValue &&
|
|
3364
|
+
!this.template.lstActionStatus?.find((x) => x.Code === this.inputActionRoleValue)) {
|
|
3365
|
+
this.template.lstActionStatus = this.template.lstActionStatus
|
|
3366
|
+
? [...this.template.lstActionStatus, { Code: this.inputValue }]
|
|
3367
|
+
: [{ Code: this.inputValue }];
|
|
3368
|
+
}
|
|
3369
|
+
this.inputActionRoleValue = '';
|
|
3370
|
+
}
|
|
3371
|
+
//#endregion
|
|
3234
3372
|
//#region Action status
|
|
3235
3373
|
inputVisible = false;
|
|
3236
3374
|
inputValue = '';
|
|
@@ -3283,7 +3421,7 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3283
3421
|
this.isSelecting = true;
|
|
3284
3422
|
this.selectStart = p;
|
|
3285
3423
|
this.selectEnd = p;
|
|
3286
|
-
this.
|
|
3424
|
+
this.lstSelectedStageId.clear();
|
|
3287
3425
|
}
|
|
3288
3426
|
onMouseMoveCanvas(event) {
|
|
3289
3427
|
if (this.isPanning && this.panStart) {
|
|
@@ -3344,9 +3482,9 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3344
3482
|
let maxX = -Infinity;
|
|
3345
3483
|
let maxY = -Infinity;
|
|
3346
3484
|
for (const n of this.lstStage) {
|
|
3347
|
-
if (!this.
|
|
3485
|
+
if (!this.lstSelectedStageId.has(n.WF_TemplateStage_Id))
|
|
3348
3486
|
continue;
|
|
3349
|
-
const start = this.dragStartPositions.get(n.
|
|
3487
|
+
const start = this.dragStartPositions.get(n.WF_TemplateStage_Id);
|
|
3350
3488
|
minX = Math.min(minX, start.x);
|
|
3351
3489
|
minY = Math.min(minY, start.y);
|
|
3352
3490
|
maxX = Math.max(maxX, start.x + nodeW);
|
|
@@ -3357,17 +3495,17 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3357
3495
|
const clampedDy = this.clamp(sdy, -minY, this.CANVAS_HEIGHT - maxY);
|
|
3358
3496
|
// 🔹 move nodes
|
|
3359
3497
|
for (const n of this.lstStage) {
|
|
3360
|
-
if (!this.
|
|
3498
|
+
if (!this.lstSelectedStageId.has(n.WF_TemplateStage_Id))
|
|
3361
3499
|
continue;
|
|
3362
|
-
const start = this.dragStartPositions.get(n.
|
|
3363
|
-
n.x = start.x + clampedDx;
|
|
3364
|
-
n.y = start.y + clampedDy;
|
|
3500
|
+
const start = this.dragStartPositions.get(n.WF_TemplateStage_Id);
|
|
3501
|
+
n.editorOption.x = start.x + clampedDx;
|
|
3502
|
+
n.editorOption.y = start.y + clampedDy;
|
|
3365
3503
|
}
|
|
3366
3504
|
// 🔹 move edge points
|
|
3367
3505
|
for (const [edge, startPoints] of this.dragStartEdgePoints.entries()) {
|
|
3368
|
-
if (!edge.points)
|
|
3506
|
+
if (!edge.editorOption.points)
|
|
3369
3507
|
continue;
|
|
3370
|
-
edge.points.forEach((pt, i) => {
|
|
3508
|
+
edge.editorOption.points.forEach((pt, i) => {
|
|
3371
3509
|
pt.x = startPoints[i].x + dx;
|
|
3372
3510
|
pt.y = startPoints[i].y + dy;
|
|
3373
3511
|
});
|
|
@@ -3391,18 +3529,18 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3391
3529
|
let rawY = p.y - this.offsetY;
|
|
3392
3530
|
// ⭐ khoá trục
|
|
3393
3531
|
if (event.shiftKey && this.axisLock === 'x') {
|
|
3394
|
-
rawY = this.draggingNode.y;
|
|
3532
|
+
rawY = this.draggingNode.editorOption.y;
|
|
3395
3533
|
}
|
|
3396
3534
|
if (event.shiftKey && this.axisLock === 'y') {
|
|
3397
|
-
rawX = this.draggingNode.x;
|
|
3535
|
+
rawX = this.draggingNode.editorOption.x;
|
|
3398
3536
|
}
|
|
3399
3537
|
const snap = this.snapPoint({ x: rawX, y: rawY }, event);
|
|
3400
3538
|
// this.draggingNode.x = snap.x;
|
|
3401
3539
|
// this.draggingNode.y = snap.y;
|
|
3402
3540
|
const nodeW = this.NODE_WIDTH;
|
|
3403
3541
|
const nodeH = this.NODE_HEIGHT;
|
|
3404
|
-
this.draggingNode.x = this.clamp(snap.x, 0, this.CANVAS_WIDTH - nodeW);
|
|
3405
|
-
this.draggingNode.y = this.clamp(snap.y, 0, this.CANVAS_HEIGHT - nodeH);
|
|
3542
|
+
this.draggingNode.editorOption.x = this.clamp(snap.x, 0, this.CANVAS_WIDTH - nodeW);
|
|
3543
|
+
this.draggingNode.editorOption.y = this.clamp(snap.y, 0, this.CANVAS_HEIGHT - nodeH);
|
|
3406
3544
|
return;
|
|
3407
3545
|
}
|
|
3408
3546
|
// 3️⃣ đang kéo waypoint
|
|
@@ -3449,74 +3587,80 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3449
3587
|
this.axisLock = null;
|
|
3450
3588
|
const p = this.getSvgPoint(event);
|
|
3451
3589
|
// CASE 1️⃣: node nằm trong selection → kéo cả group
|
|
3452
|
-
if (this.
|
|
3590
|
+
if (this.lstSelectedStageId.has(node.WF_TemplateStage_Id)) {
|
|
3453
3591
|
/* =============================
|
|
3454
3592
|
* UNDO SNAPSHOT (GROUP)
|
|
3455
3593
|
* ============================= */
|
|
3456
3594
|
this.pushUndo({
|
|
3457
3595
|
type: 'move-nodes',
|
|
3458
|
-
before: this.cloneNodePositions(this.
|
|
3596
|
+
before: this.cloneNodePositions(this.lstSelectedStageId),
|
|
3459
3597
|
});
|
|
3460
3598
|
this.draggingGroup = true;
|
|
3461
3599
|
this.dragStartMouse = p;
|
|
3462
3600
|
// 🔹 snapshot node positions
|
|
3463
3601
|
this.dragStartPositions.clear();
|
|
3464
3602
|
for (const n of this.lstStage) {
|
|
3465
|
-
if (this.
|
|
3466
|
-
this.dragStartPositions.set(n.
|
|
3603
|
+
if (this.lstSelectedStageId.has(n.WF_TemplateStage_Id)) {
|
|
3604
|
+
this.dragStartPositions.set(n.WF_TemplateStage_Id, { x: n.editorOption.x, y: n.editorOption.y });
|
|
3467
3605
|
}
|
|
3468
3606
|
}
|
|
3469
3607
|
// 🔹 snapshot edge points
|
|
3470
3608
|
this.dragStartEdgePoints = new Map();
|
|
3471
3609
|
for (const e of this.lstAction) {
|
|
3472
|
-
if (!e.points?.length)
|
|
3610
|
+
if (!e.editorOption.points?.length)
|
|
3473
3611
|
continue;
|
|
3474
|
-
if (this.
|
|
3475
|
-
this.
|
|
3612
|
+
if (this.lstSelectedStageId.has(e.WF_TemplateStage_Id) ||
|
|
3613
|
+
this.lstSelectedStageId.has(e.To_WF_TemplateStage_Id)) {
|
|
3614
|
+
this.dragStartEdgePoints.set(e, e.editorOption.points.map((p) => ({ x: p.x, y: p.y })));
|
|
3476
3615
|
}
|
|
3477
3616
|
}
|
|
3478
3617
|
return;
|
|
3479
3618
|
}
|
|
3480
3619
|
// CASE 2️⃣: node chưa được chọn → kéo node đơn
|
|
3481
|
-
this.
|
|
3620
|
+
this.lstSelectedStageId.clear();
|
|
3482
3621
|
// this.selectedNodeIds.add(node.id);
|
|
3483
3622
|
/* =============================
|
|
3484
3623
|
* UNDO SNAPSHOT (1 NODE)
|
|
3485
3624
|
* ============================= */
|
|
3486
3625
|
this.pushUndo({
|
|
3487
3626
|
type: 'move-nodes',
|
|
3488
|
-
before: this.cloneNodePositions(new Set([node.
|
|
3627
|
+
before: this.cloneNodePositions(new Set([node.WF_TemplateStage_Id])),
|
|
3489
3628
|
});
|
|
3490
3629
|
this.draggingNode = node;
|
|
3491
3630
|
this.dragStartX = event.clientX;
|
|
3492
3631
|
this.dragStartY = event.clientY;
|
|
3493
|
-
this.offsetX = event.clientX - node.x;
|
|
3494
|
-
this.offsetY = event.clientY - node.y;
|
|
3632
|
+
this.offsetX = event.clientX - node.editorOption.x;
|
|
3633
|
+
this.offsetY = event.clientY - node.editorOption.y;
|
|
3495
3634
|
this.isDragging = false;
|
|
3496
3635
|
}
|
|
3497
3636
|
onClickStage(node) {
|
|
3498
3637
|
console.log('onClickStage', node);
|
|
3499
3638
|
this.hoverStage = undefined;
|
|
3639
|
+
this.selectedStage = undefined;
|
|
3500
3640
|
if (this.isDragging)
|
|
3501
3641
|
return;
|
|
3502
3642
|
if (this.connectingFrom) {
|
|
3503
|
-
if (this.connectingFrom.node.
|
|
3504
|
-
const existed = this.lstAction.some((e) => e.
|
|
3643
|
+
if (this.connectingFrom.node.WF_TemplateStage_Id !== node.WF_TemplateStage_Id) {
|
|
3644
|
+
const existed = this.lstAction.some((e) => e.WF_TemplateStage_Id === this.connectingFrom.node.WF_TemplateStage_Id &&
|
|
3645
|
+
e.To_WF_TemplateStage_Id === node.WF_TemplateStage_Id);
|
|
3505
3646
|
if (!existed) {
|
|
3506
3647
|
const newAction = new WorkflowAction();
|
|
3507
|
-
newAction.
|
|
3648
|
+
newAction.WF_TemplateStage_Id = this.connectingFrom.node.WF_TemplateStage_Id;
|
|
3508
3649
|
newAction.FromSide = this.connectingFrom.side;
|
|
3509
|
-
newAction.
|
|
3650
|
+
newAction.To_WF_TemplateStage_Id = node.WF_TemplateStage_Id;
|
|
3510
3651
|
newAction.ToSide = 'left';
|
|
3511
3652
|
// ⭐ NẾU CÓ WAYPOINT → MANUAL ROUTE
|
|
3512
3653
|
if (this.connectingPoints.length > 0) {
|
|
3513
|
-
newAction.points = [...this.connectingPoints];
|
|
3654
|
+
newAction.editorOption.points = [...this.connectingPoints];
|
|
3514
3655
|
}
|
|
3515
3656
|
this.lstAction.push(newAction);
|
|
3516
|
-
const stage = this.lstStage.find((x) => x.
|
|
3657
|
+
const stage = this.lstStage.find((x) => x.WF_TemplateStage_Id == newAction.WF_TemplateStage_Id);
|
|
3517
3658
|
if (stage) {
|
|
3518
3659
|
stage.lstAction = stage.lstAction ? [...stage.lstAction, newAction] : [newAction];
|
|
3519
3660
|
}
|
|
3661
|
+
console.log('from action', this.connectingFrom.node);
|
|
3662
|
+
console.log('to action', node);
|
|
3663
|
+
console.log('newAction', newAction);
|
|
3520
3664
|
}
|
|
3521
3665
|
}
|
|
3522
3666
|
this.cancelConnecting();
|
|
@@ -3524,11 +3668,11 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3524
3668
|
}
|
|
3525
3669
|
if (this.isDragging)
|
|
3526
3670
|
return;
|
|
3527
|
-
if (this.
|
|
3671
|
+
if (this.lstSelectedStageId.size)
|
|
3528
3672
|
return;
|
|
3529
3673
|
// if (node.id == 'start' || node.id == 'end') return;
|
|
3674
|
+
this.hoverStage = node;
|
|
3530
3675
|
this.selectedStage = node;
|
|
3531
|
-
console.log(this.selectedStage);
|
|
3532
3676
|
}
|
|
3533
3677
|
//#endregion
|
|
3534
3678
|
//#region EDGE action
|
|
@@ -3537,7 +3681,7 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3537
3681
|
if (this.connectingFrom)
|
|
3538
3682
|
return;
|
|
3539
3683
|
this.hoverAction = e;
|
|
3540
|
-
this.connectingPoints = e.points || [];
|
|
3684
|
+
this.connectingPoints = e.editorOption.points || [];
|
|
3541
3685
|
}
|
|
3542
3686
|
onMouseLeaveEdge(e) {
|
|
3543
3687
|
// console.log('onEdgeLeave', e);
|
|
@@ -3559,10 +3703,14 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3559
3703
|
return;
|
|
3560
3704
|
}
|
|
3561
3705
|
if (doAction) {
|
|
3562
|
-
|
|
3563
|
-
this.
|
|
3564
|
-
|
|
3565
|
-
|
|
3706
|
+
// k cấu hình ở đây nữa, cấu trong stage
|
|
3707
|
+
// this.selectedAction = edge;
|
|
3708
|
+
// this.selectedBackAction = this.lstAction.find(
|
|
3709
|
+
// (x) =>
|
|
3710
|
+
// x.isBackAction == true &&
|
|
3711
|
+
// x.WF_TemplateStage_Id == this.selectedAction?.To_WF_TemplateStage_Id &&
|
|
3712
|
+
// x.To_WF_TemplateStage_Id == this.selectedAction?.WF_TemplateStage_Id,
|
|
3713
|
+
// );
|
|
3566
3714
|
}
|
|
3567
3715
|
else {
|
|
3568
3716
|
// 👉 SINGLE CLICK (chờ xem có dbl không)
|
|
@@ -3579,11 +3727,11 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3579
3727
|
event.preventDefault();
|
|
3580
3728
|
const p = this.getSvgPoint(event, true);
|
|
3581
3729
|
// Nếu edge chưa có manual points → convert auto → manual
|
|
3582
|
-
if (!edge.points || edge.points.length === 0) {
|
|
3583
|
-
edge.points = [];
|
|
3730
|
+
if (!edge.editorOption.points || edge.editorOption.points.length === 0) {
|
|
3731
|
+
edge.editorOption.points = [];
|
|
3584
3732
|
}
|
|
3585
3733
|
const insertIndex = this.findInsertIndex(edge, p);
|
|
3586
|
-
edge.points.splice(insertIndex, 0, {
|
|
3734
|
+
edge.editorOption.points.splice(insertIndex, 0, {
|
|
3587
3735
|
x: p.x,
|
|
3588
3736
|
y: p.y,
|
|
3589
3737
|
});
|
|
@@ -3612,20 +3760,21 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3612
3760
|
* CLICK IN (LEFT) → KẾT THÚC
|
|
3613
3761
|
* ============================= */
|
|
3614
3762
|
if (side === 'left' && this.connectingFrom) {
|
|
3615
|
-
if (this.connectingFrom.node.
|
|
3616
|
-
const existed = this.lstAction.some((e) => e.
|
|
3763
|
+
if (this.connectingFrom.node.WF_TemplateStage_Id !== node.WF_TemplateStage_Id) {
|
|
3764
|
+
const existed = this.lstAction.some((e) => e.WF_TemplateStage_Id === this.connectingFrom.node.WF_TemplateStage_Id &&
|
|
3765
|
+
e.To_WF_TemplateStage_Id === node.WF_TemplateStage_Id);
|
|
3617
3766
|
if (!existed) {
|
|
3618
3767
|
const newAction = new WorkflowAction();
|
|
3619
|
-
newAction.
|
|
3768
|
+
newAction.WF_TemplateStage_Id = this.connectingFrom.node.WF_TemplateStage_Id;
|
|
3620
3769
|
newAction.FromSide = this.connectingFrom.side;
|
|
3621
|
-
newAction.
|
|
3770
|
+
newAction.To_WF_TemplateStage_Id = node.WF_TemplateStage_Id;
|
|
3622
3771
|
newAction.ToSide = 'left';
|
|
3623
3772
|
// ⭐ NẾU CÓ WAYPOINT → MANUAL ROUTE
|
|
3624
3773
|
if (this.connectingPoints.length > 0) {
|
|
3625
|
-
newAction.points = [...this.connectingPoints];
|
|
3774
|
+
newAction.editorOption.points = [...this.connectingPoints];
|
|
3626
3775
|
}
|
|
3627
3776
|
this.lstAction.push(newAction);
|
|
3628
|
-
const stage = this.lstStage.find((x) => x.
|
|
3777
|
+
const stage = this.lstStage.find((x) => x.WF_TemplateStage_Id == newAction.WF_TemplateStage_Id);
|
|
3629
3778
|
if (stage) {
|
|
3630
3779
|
stage.lstAction = stage.lstAction ? [...stage.lstAction, newAction] : [newAction];
|
|
3631
3780
|
}
|
|
@@ -3653,13 +3802,9 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3653
3802
|
console.log('onRightClickPoint', edge, index);
|
|
3654
3803
|
event.preventDefault();
|
|
3655
3804
|
event.stopPropagation();
|
|
3656
|
-
if (!edge.points)
|
|
3805
|
+
if (!edge.editorOption.points)
|
|
3657
3806
|
return;
|
|
3658
|
-
edge.points.splice(index, 1);
|
|
3659
|
-
// Nếu xoá hết → quay về auto route
|
|
3660
|
-
if (edge.points.length === 0) {
|
|
3661
|
-
delete edge.points;
|
|
3662
|
-
}
|
|
3807
|
+
edge.editorOption.points.splice(index, 1);
|
|
3663
3808
|
}
|
|
3664
3809
|
//#endregion
|
|
3665
3810
|
//#region UNDO REDU
|
|
@@ -3668,8 +3813,8 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3668
3813
|
cloneNodePositions(nodeIds) {
|
|
3669
3814
|
const map = new Map();
|
|
3670
3815
|
for (const n of this.lstStage) {
|
|
3671
|
-
if (nodeIds.has(n.
|
|
3672
|
-
map.set(n.
|
|
3816
|
+
if (nodeIds.has(n.WF_TemplateStage_Id)) {
|
|
3817
|
+
map.set(n.WF_TemplateStage_Id, { x: n.editorOption.x, y: n.editorOption.y });
|
|
3673
3818
|
}
|
|
3674
3819
|
}
|
|
3675
3820
|
return map;
|
|
@@ -3677,7 +3822,7 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3677
3822
|
pushAlignUndo() {
|
|
3678
3823
|
this.pushUndo({
|
|
3679
3824
|
type: 'move-nodes',
|
|
3680
|
-
before: this.cloneNodePositions(this.
|
|
3825
|
+
before: this.cloneNodePositions(this.lstSelectedStageId),
|
|
3681
3826
|
});
|
|
3682
3827
|
}
|
|
3683
3828
|
pushUndo(action) {
|
|
@@ -3711,10 +3856,10 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3711
3856
|
});
|
|
3712
3857
|
// restore
|
|
3713
3858
|
action.before.forEach((pos, id) => {
|
|
3714
|
-
const node = this.lstStage.find((n) => n.
|
|
3859
|
+
const node = this.lstStage.find((n) => n.WF_TemplateStage_Id === id);
|
|
3715
3860
|
if (node) {
|
|
3716
|
-
node.x = pos.x;
|
|
3717
|
-
node.y = pos.y;
|
|
3861
|
+
node.editorOption.x = pos.x;
|
|
3862
|
+
node.editorOption.y = pos.y;
|
|
3718
3863
|
}
|
|
3719
3864
|
});
|
|
3720
3865
|
}
|
|
@@ -3729,8 +3874,8 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3729
3874
|
case 'delete-node': {
|
|
3730
3875
|
const nodeId = action.node.id;
|
|
3731
3876
|
// redo = xoá lại
|
|
3732
|
-
this.lstAction = this.lstAction.filter((e) => e.
|
|
3733
|
-
const idx = this.lstStage.findIndex((n) => n.
|
|
3877
|
+
this.lstAction = this.lstAction.filter((e) => e.WF_TemplateStage_Id !== nodeId && e.To_WF_TemplateStage_Id !== nodeId);
|
|
3878
|
+
const idx = this.lstStage.findIndex((n) => n.WF_TemplateStage_Id === nodeId);
|
|
3734
3879
|
if (idx >= 0)
|
|
3735
3880
|
this.lstStage.splice(idx, 1);
|
|
3736
3881
|
this.undoStack.push(action);
|
|
@@ -3745,10 +3890,10 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3745
3890
|
before: after,
|
|
3746
3891
|
});
|
|
3747
3892
|
action.before.forEach((pos, id) => {
|
|
3748
|
-
const node = this.lstStage.find((n) => n.
|
|
3893
|
+
const node = this.lstStage.find((n) => n.WF_TemplateStage_Id === id);
|
|
3749
3894
|
if (node) {
|
|
3750
|
-
node.x = pos.x;
|
|
3751
|
-
node.y = pos.y;
|
|
3895
|
+
node.editorOption.x = pos.x;
|
|
3896
|
+
node.editorOption.y = pos.y;
|
|
3752
3897
|
}
|
|
3753
3898
|
});
|
|
3754
3899
|
}
|
|
@@ -3761,97 +3906,97 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3761
3906
|
NODE_HEIGHT = 80;
|
|
3762
3907
|
//#region ALIGN
|
|
3763
3908
|
getSelectedNodes() {
|
|
3764
|
-
return this.lstStage.filter((n) => this.
|
|
3909
|
+
return this.lstStage.filter((n) => this.lstSelectedStageId.has(n.WF_TemplateStage_Id));
|
|
3765
3910
|
}
|
|
3766
3911
|
alignLeft() {
|
|
3767
|
-
if (this.
|
|
3912
|
+
if (this.lstSelectedStageId.size < 2)
|
|
3768
3913
|
return;
|
|
3769
3914
|
this.pushAlignUndo();
|
|
3770
3915
|
const nodes = this.getSelectedNodes();
|
|
3771
|
-
const minX = Math.min(...nodes.map((n) => n.x));
|
|
3772
|
-
nodes.forEach((n) => (n.x = minX));
|
|
3916
|
+
const minX = Math.min(...nodes.map((n) => n.editorOption.x));
|
|
3917
|
+
nodes.forEach((n) => (n.editorOption.x = minX));
|
|
3773
3918
|
}
|
|
3774
3919
|
alignCenter() {
|
|
3775
|
-
if (this.
|
|
3920
|
+
if (this.lstSelectedStageId.size < 2)
|
|
3776
3921
|
return;
|
|
3777
3922
|
this.pushAlignUndo();
|
|
3778
3923
|
const nodes = this.getSelectedNodes();
|
|
3779
|
-
const centers = nodes.map((n) => n.x + this.NODE_WIDTH / 2);
|
|
3924
|
+
const centers = nodes.map((n) => n.editorOption.x + this.NODE_WIDTH / 2);
|
|
3780
3925
|
const centerX = centers.reduce((a, b) => a + b) / centers.length;
|
|
3781
3926
|
nodes.forEach((n) => {
|
|
3782
|
-
n.x = centerX - this.NODE_WIDTH / 2;
|
|
3927
|
+
n.editorOption.x = centerX - this.NODE_WIDTH / 2;
|
|
3783
3928
|
});
|
|
3784
3929
|
}
|
|
3785
3930
|
alignRight() {
|
|
3786
|
-
if (this.
|
|
3931
|
+
if (this.lstSelectedStageId.size < 2)
|
|
3787
3932
|
return;
|
|
3788
3933
|
this.pushAlignUndo();
|
|
3789
3934
|
const nodes = this.getSelectedNodes();
|
|
3790
|
-
const maxX = Math.max(...nodes.map((n) => n.x + this.NODE_WIDTH));
|
|
3791
|
-
nodes.forEach((n) => (n.x = maxX - this.NODE_WIDTH));
|
|
3935
|
+
const maxX = Math.max(...nodes.map((n) => n.editorOption.x + this.NODE_WIDTH));
|
|
3936
|
+
nodes.forEach((n) => (n.editorOption.x = maxX - this.NODE_WIDTH));
|
|
3792
3937
|
}
|
|
3793
3938
|
alignTop() {
|
|
3794
|
-
if (this.
|
|
3939
|
+
if (this.lstSelectedStageId.size < 2)
|
|
3795
3940
|
return;
|
|
3796
3941
|
this.pushAlignUndo();
|
|
3797
3942
|
const nodes = this.getSelectedNodes();
|
|
3798
|
-
const minY = Math.min(...nodes.map((n) => n.y));
|
|
3799
|
-
nodes.forEach((n) => (n.y = minY));
|
|
3943
|
+
const minY = Math.min(...nodes.map((n) => n.editorOption.y));
|
|
3944
|
+
nodes.forEach((n) => (n.editorOption.y = minY));
|
|
3800
3945
|
}
|
|
3801
3946
|
alignMiddle() {
|
|
3802
|
-
if (this.
|
|
3947
|
+
if (this.lstSelectedStageId.size < 2)
|
|
3803
3948
|
return;
|
|
3804
3949
|
this.pushAlignUndo();
|
|
3805
3950
|
const nodes = this.getSelectedNodes();
|
|
3806
|
-
const centers = nodes.map((n) => n.y + this.NODE_HEIGHT / 2);
|
|
3951
|
+
const centers = nodes.map((n) => n.editorOption.y + this.NODE_HEIGHT / 2);
|
|
3807
3952
|
const centerY = centers.reduce((a, b) => a + b) / centers.length;
|
|
3808
3953
|
nodes.forEach((n) => {
|
|
3809
|
-
n.y = centerY - this.NODE_HEIGHT / 2;
|
|
3954
|
+
n.editorOption.y = centerY - this.NODE_HEIGHT / 2;
|
|
3810
3955
|
});
|
|
3811
3956
|
}
|
|
3812
3957
|
alignBottom() {
|
|
3813
|
-
if (this.
|
|
3958
|
+
if (this.lstSelectedStageId.size < 2)
|
|
3814
3959
|
return;
|
|
3815
3960
|
this.pushAlignUndo();
|
|
3816
3961
|
const nodes = this.getSelectedNodes();
|
|
3817
|
-
const maxY = Math.max(...nodes.map((n) => n.y + this.NODE_HEIGHT));
|
|
3818
|
-
nodes.forEach((n) => (n.y = maxY - this.NODE_HEIGHT));
|
|
3962
|
+
const maxY = Math.max(...nodes.map((n) => n.editorOption.y + this.NODE_HEIGHT));
|
|
3963
|
+
nodes.forEach((n) => (n.editorOption.y = maxY - this.NODE_HEIGHT));
|
|
3819
3964
|
}
|
|
3820
3965
|
distributeHorizontal() {
|
|
3821
|
-
if (this.
|
|
3966
|
+
if (this.lstSelectedStageId.size < 3)
|
|
3822
3967
|
return;
|
|
3823
3968
|
this.pushAlignUndo();
|
|
3824
|
-
const nodes = this.getSelectedNodes().sort((a, b) => a.x - b.x);
|
|
3969
|
+
const nodes = this.getSelectedNodes().sort((a, b) => a.editorOption.x - b.editorOption.x);
|
|
3825
3970
|
const first = nodes[0];
|
|
3826
3971
|
const last = nodes[nodes.length - 1];
|
|
3827
3972
|
const totalWidth = nodes.reduce((s, n) => s + this.NODE_WIDTH, 0);
|
|
3828
|
-
const space = (last.x - first.x - totalWidth + this.NODE_WIDTH) / (nodes.length - 1);
|
|
3829
|
-
let x = first.x;
|
|
3973
|
+
const space = (last.editorOption.x - first.editorOption.x - totalWidth + this.NODE_WIDTH) / (nodes.length - 1);
|
|
3974
|
+
let x = first.editorOption.x;
|
|
3830
3975
|
nodes.forEach((n, i) => {
|
|
3831
3976
|
if (i === 0 || i === nodes.length - 1) {
|
|
3832
|
-
x = n.x + this.NODE_WIDTH + space;
|
|
3977
|
+
x = n.editorOption.x + this.NODE_WIDTH + space;
|
|
3833
3978
|
return;
|
|
3834
3979
|
}
|
|
3835
|
-
n.x = x;
|
|
3980
|
+
n.editorOption.x = x;
|
|
3836
3981
|
x += this.NODE_WIDTH + space;
|
|
3837
3982
|
});
|
|
3838
3983
|
}
|
|
3839
3984
|
distributeVertical() {
|
|
3840
|
-
if (this.
|
|
3985
|
+
if (this.lstSelectedStageId.size < 3)
|
|
3841
3986
|
return;
|
|
3842
3987
|
this.pushAlignUndo();
|
|
3843
|
-
const nodes = this.getSelectedNodes().sort((a, b) => a.y - b.y);
|
|
3988
|
+
const nodes = this.getSelectedNodes().sort((a, b) => a.editorOption.y - b.editorOption.y);
|
|
3844
3989
|
const first = nodes[0];
|
|
3845
3990
|
const last = nodes[nodes.length - 1];
|
|
3846
3991
|
const totalHeight = nodes.reduce((s, n) => s + this.NODE_HEIGHT, 0);
|
|
3847
|
-
const space = (last.y - first.y - totalHeight + this.NODE_HEIGHT) / (nodes.length - 1);
|
|
3848
|
-
let y = first.y;
|
|
3992
|
+
const space = (last.editorOption.y - first.editorOption.y - totalHeight + this.NODE_HEIGHT) / (nodes.length - 1);
|
|
3993
|
+
let y = first.editorOption.y;
|
|
3849
3994
|
nodes.forEach((n, i) => {
|
|
3850
3995
|
if (i === 0 || i === nodes.length - 1) {
|
|
3851
|
-
y = n.y + this.NODE_HEIGHT + space;
|
|
3996
|
+
y = n.editorOption.y + this.NODE_HEIGHT + space;
|
|
3852
3997
|
return;
|
|
3853
3998
|
}
|
|
3854
|
-
n.y = y;
|
|
3999
|
+
n.editorOption.y = y;
|
|
3855
4000
|
y += this.NODE_HEIGHT + space;
|
|
3856
4001
|
});
|
|
3857
4002
|
}
|
|
@@ -3879,19 +4024,27 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3879
4024
|
//#endregion
|
|
3880
4025
|
//#region HELPER
|
|
3881
4026
|
isEdgeReversed(edge) {
|
|
3882
|
-
const
|
|
3883
|
-
const
|
|
4027
|
+
const x = this.lstStage.find((x) => x.WF_TemplateStage_Id == edge.WF_TemplateStage_Id);
|
|
4028
|
+
const y = this.lstStage.find((x) => x.WF_TemplateStage_Id == edge.To_WF_TemplateStage_Id);
|
|
4029
|
+
if (!x || !y)
|
|
4030
|
+
return false;
|
|
4031
|
+
const from = this.getNodeCenter(x, 'right');
|
|
4032
|
+
const to = this.getNodeCenter(y, 'left');
|
|
3884
4033
|
return to.x < from.x;
|
|
3885
4034
|
}
|
|
3886
4035
|
getEdgeLabelPosition(edge) {
|
|
3887
4036
|
// Ưu tiên waypoint giữa nếu có
|
|
3888
|
-
if (edge.points && edge.points.length > 0) {
|
|
3889
|
-
const mid = edge.points[Math.floor(edge.points.length / 2)];
|
|
4037
|
+
if (edge.editorOption.points && edge.editorOption.points.length > 0) {
|
|
4038
|
+
const mid = edge.editorOption.points[Math.floor(edge.editorOption.points.length / 2)];
|
|
3890
4039
|
return { x: mid.x, y: mid.y };
|
|
3891
4040
|
}
|
|
3892
4041
|
// fallback: giữa from → to
|
|
3893
|
-
const
|
|
3894
|
-
const
|
|
4042
|
+
const x = this.lstStage.find((x) => x.WF_TemplateStage_Id == edge.WF_TemplateStage_Id);
|
|
4043
|
+
const y = this.lstStage.find((x) => x.WF_TemplateStage_Id == edge.To_WF_TemplateStage_Id);
|
|
4044
|
+
if (!x || !y)
|
|
4045
|
+
return { x: 0, y: 0 };
|
|
4046
|
+
const from = this.getNodeCenter(x, 'right');
|
|
4047
|
+
const to = this.getNodeCenter(y, 'left');
|
|
3895
4048
|
return {
|
|
3896
4049
|
x: (from.x + to.x) / 2,
|
|
3897
4050
|
y: (from.y + to.y) / 2,
|
|
@@ -3905,23 +4058,23 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3905
4058
|
switch (side) {
|
|
3906
4059
|
case 'left':
|
|
3907
4060
|
return {
|
|
3908
|
-
x: node.x,
|
|
3909
|
-
y: node.y + height / 2,
|
|
4061
|
+
x: node.editorOption.x,
|
|
4062
|
+
y: node.editorOption.y + height / 2,
|
|
3910
4063
|
};
|
|
3911
4064
|
case 'right':
|
|
3912
4065
|
return {
|
|
3913
|
-
x: node.x + width,
|
|
3914
|
-
y: node.y + height / 2,
|
|
4066
|
+
x: node.editorOption.x + width,
|
|
4067
|
+
y: node.editorOption.y + height / 2,
|
|
3915
4068
|
};
|
|
3916
4069
|
case 'top':
|
|
3917
4070
|
return {
|
|
3918
|
-
x: node.x + width / 2,
|
|
3919
|
-
y: node.y,
|
|
4071
|
+
x: node.editorOption.x + width / 2,
|
|
4072
|
+
y: node.editorOption.y,
|
|
3920
4073
|
};
|
|
3921
4074
|
case 'bottom':
|
|
3922
4075
|
return {
|
|
3923
|
-
x: node.x + width / 2,
|
|
3924
|
-
y: node.y + height,
|
|
4076
|
+
x: node.editorOption.x + width / 2,
|
|
4077
|
+
y: node.editorOption.y + height,
|
|
3925
4078
|
};
|
|
3926
4079
|
}
|
|
3927
4080
|
}
|
|
@@ -3950,11 +4103,15 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3950
4103
|
return Math.max(0, index);
|
|
3951
4104
|
}
|
|
3952
4105
|
getEdgeFullPoints(edge) {
|
|
3953
|
-
if (!edge.
|
|
4106
|
+
if (!edge.WF_TemplateStage_Id || !edge.To_WF_TemplateStage_Id)
|
|
3954
4107
|
return null;
|
|
3955
|
-
const from = this.getNode(edge.
|
|
3956
|
-
const to = this.getNode(edge.
|
|
3957
|
-
return [
|
|
4108
|
+
const from = this.getNode(edge.WF_TemplateStage_Id);
|
|
4109
|
+
const to = this.getNode(edge.To_WF_TemplateStage_Id);
|
|
4110
|
+
return [
|
|
4111
|
+
{ x: from.editorOption.x + 160, y: from.editorOption.y + 40 },
|
|
4112
|
+
...(edge.editorOption.points || []),
|
|
4113
|
+
{ x: to.editorOption.x, y: to.editorOption.y + 40 },
|
|
4114
|
+
];
|
|
3958
4115
|
}
|
|
3959
4116
|
pointToSegmentDistance(p, a, b) {
|
|
3960
4117
|
const dx = b.x - a.x;
|
|
@@ -3971,20 +4128,20 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
3971
4128
|
return Math.hypot(p.x - proj.x, p.y - proj.y);
|
|
3972
4129
|
}
|
|
3973
4130
|
isPositionOccupied(x, y) {
|
|
3974
|
-
return this.lstStage.some((n) => Math.abs(n.x - x) < 160 && Math.abs(n.y - y) < 80);
|
|
4131
|
+
return this.lstStage.some((n) => Math.abs(n.editorOption?.x - x) < 160 && Math.abs(n.editorOption?.y - y) < 80);
|
|
3975
4132
|
}
|
|
3976
4133
|
getCanvasWidth() {
|
|
3977
4134
|
// return 3000;
|
|
3978
4135
|
const PADDING = 200;
|
|
3979
4136
|
const MIN_WIDTH = 800;
|
|
3980
|
-
const maxX = Math.max(...this.lstStage.map((n) => (n.StageType == 'END' ? n.x : n.x + 160)), // 160 = node width
|
|
4137
|
+
const maxX = Math.max(...this.lstStage.map((n) => (n.StageType == 'END' ? n.editorOption?.x : n.editorOption?.x + 160)), // 160 = node width
|
|
3981
4138
|
MIN_WIDTH);
|
|
3982
4139
|
return maxX + PADDING;
|
|
3983
4140
|
}
|
|
3984
4141
|
getCanvasHeight() {
|
|
3985
4142
|
// return 2000;
|
|
3986
4143
|
const PADDING = 100;
|
|
3987
|
-
const maxY = Math.max(...this.lstStage.map((n) => n.y + 80), 400);
|
|
4144
|
+
const maxY = Math.max(...this.lstStage.map((n) => n.editorOption?.y + 80), 400);
|
|
3988
4145
|
return maxY + PADDING;
|
|
3989
4146
|
}
|
|
3990
4147
|
/* =============================
|
|
@@ -4010,15 +4167,15 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
4010
4167
|
const y1 = Math.min(this.selectStart.y, this.selectEnd.y);
|
|
4011
4168
|
const x2 = Math.max(this.selectStart.x, this.selectEnd.x);
|
|
4012
4169
|
const y2 = Math.max(this.selectStart.y, this.selectEnd.y);
|
|
4013
|
-
this.
|
|
4170
|
+
this.lstSelectedStageId.clear();
|
|
4014
4171
|
for (const n of this.lstStage) {
|
|
4015
|
-
const nx1 = n.x;
|
|
4016
|
-
const ny1 = n.y;
|
|
4017
|
-
const nx2 = n.x + 160;
|
|
4018
|
-
const ny2 = n.y + 80;
|
|
4172
|
+
const nx1 = n.editorOption.x;
|
|
4173
|
+
const ny1 = n.editorOption.y;
|
|
4174
|
+
const nx2 = n.editorOption.x + 160;
|
|
4175
|
+
const ny2 = n.editorOption.y + 80;
|
|
4019
4176
|
const intersect = nx2 >= x1 && nx1 <= x2 && ny2 >= y1 && ny1 <= y2;
|
|
4020
4177
|
if (intersect) {
|
|
4021
|
-
this.
|
|
4178
|
+
this.lstSelectedStageId.add(n.WF_TemplateStage_Id);
|
|
4022
4179
|
}
|
|
4023
4180
|
}
|
|
4024
4181
|
}
|
|
@@ -4036,25 +4193,25 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
4036
4193
|
return Math.round(value / this.gridSize) * this.gridSize;
|
|
4037
4194
|
}
|
|
4038
4195
|
getNode(id) {
|
|
4039
|
-
return this.lstStage.find((n) => n.
|
|
4196
|
+
return this.lstStage.find((n) => n.WF_TemplateStage_Id === id);
|
|
4040
4197
|
}
|
|
4041
4198
|
//#endregion
|
|
4042
4199
|
//#region BUILD PATH
|
|
4043
4200
|
buildPath(edge) {
|
|
4044
|
-
if (!edge.
|
|
4201
|
+
if (!edge.WF_TemplateStage_Id || !edge.To_WF_TemplateStage_Id)
|
|
4045
4202
|
return '';
|
|
4046
|
-
const from = this.getNode(edge.
|
|
4047
|
-
const to = this.getNode(edge.
|
|
4203
|
+
const from = this.getNode(edge.WF_TemplateStage_Id);
|
|
4204
|
+
const to = this.getNode(edge.To_WF_TemplateStage_Id);
|
|
4048
4205
|
const start = {
|
|
4049
|
-
x: from.x + (from.isReverse ? 0 : 160),
|
|
4050
|
-
y: from.y + 40,
|
|
4206
|
+
x: from.editorOption.x + (from.editorOption.isReverse ? 0 : 160),
|
|
4207
|
+
y: from.editorOption.y + 40,
|
|
4051
4208
|
};
|
|
4052
4209
|
const end = {
|
|
4053
|
-
x: to.x + (to.isReverse ? 160 : 0),
|
|
4054
|
-
y: to.y + 40,
|
|
4210
|
+
x: to.editorOption.x + (to.editorOption.isReverse ? 160 : 0),
|
|
4211
|
+
y: to.editorOption.y + 40,
|
|
4055
4212
|
};
|
|
4056
|
-
if (edge.points && edge.points.length) {
|
|
4057
|
-
return this.buildPathThroughPoints([start, ...edge.points, end]);
|
|
4213
|
+
if (edge.editorOption.points && edge.editorOption.points.length) {
|
|
4214
|
+
return this.buildPathThroughPoints([start, ...edge.editorOption.points, end]);
|
|
4058
4215
|
}
|
|
4059
4216
|
// return this.buildRoutedPath({ node: from, side: edge.fromSide }, to.x, to.y + 40);
|
|
4060
4217
|
return this.buildStragePath(start.x, start.y, end.x, end.y);
|
|
@@ -4063,8 +4220,8 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
4063
4220
|
if (!this.connectingFrom)
|
|
4064
4221
|
return '';
|
|
4065
4222
|
const start = {
|
|
4066
|
-
x: this.connectingFrom.node.x + (this.connectingFrom.node.isReverse ? 0 : 160),
|
|
4067
|
-
y: this.connectingFrom.node.y + 40,
|
|
4223
|
+
x: this.connectingFrom.node.editorOption.x + (this.connectingFrom.node.editorOption.isReverse ? 0 : 160),
|
|
4224
|
+
y: this.connectingFrom.node.editorOption.y + 40,
|
|
4068
4225
|
};
|
|
4069
4226
|
const end = {
|
|
4070
4227
|
x: this.previewX,
|
|
@@ -4105,8 +4262,8 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
4105
4262
|
`;
|
|
4106
4263
|
}
|
|
4107
4264
|
buildRoutedPath(from, toX, toY, ARROW_GAP = 12) {
|
|
4108
|
-
const x1 = from.node.isReverse ? from.node.x : from.node.x + 160;
|
|
4109
|
-
const y1 = from.node.y + 40;
|
|
4265
|
+
const x1 = from.node.editorOption.isReverse ? from.node.editorOption.x : from.node.editorOption.x + 160;
|
|
4266
|
+
const y1 = from.node.editorOption.y + 40;
|
|
4110
4267
|
const x2 = toX;
|
|
4111
4268
|
const y2 = toY;
|
|
4112
4269
|
// const ARROW_GAP = 12;
|
|
@@ -4207,10 +4364,10 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
4207
4364
|
};
|
|
4208
4365
|
}
|
|
4209
4366
|
isBlockedPoint(from, x2, y2) {
|
|
4210
|
-
const x1 = from.node.isReverse ? from.node.x + 160 : from.node.x;
|
|
4211
|
-
const y1 = from.node.y + 40;
|
|
4367
|
+
const x1 = from.node.editorOption.isReverse ? from.node.editorOption.x + 160 : from.node.editorOption.x;
|
|
4368
|
+
const y1 = from.node.editorOption.y + 40;
|
|
4212
4369
|
return this.lstStage.some((n) => {
|
|
4213
|
-
if (n.
|
|
4370
|
+
if (n.WF_TemplateStage_Id === from.node.WF_TemplateStage_Id)
|
|
4214
4371
|
return false;
|
|
4215
4372
|
// node phải nằm giữa theo trục X
|
|
4216
4373
|
if (!this.isNodeBetweenX(x1, x2, n))
|
|
@@ -4220,7 +4377,7 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
4220
4377
|
});
|
|
4221
4378
|
}
|
|
4222
4379
|
findBestRouteY(from, toX, toY) {
|
|
4223
|
-
const baseY = from.node.y + 40;
|
|
4380
|
+
const baseY = from.node.editorOption.y + 40;
|
|
4224
4381
|
const OFFSETS = [0, 80, -80, 160, -160, 240, -240];
|
|
4225
4382
|
for (const offset of OFFSETS) {
|
|
4226
4383
|
const routeY = baseY + offset;
|
|
@@ -4232,24 +4389,24 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
4232
4389
|
return baseY + OFFSETS[OFFSETS.length - 1];
|
|
4233
4390
|
}
|
|
4234
4391
|
isNodeBetweenX(fromX, toX, node) {
|
|
4235
|
-
const nx1 = node.x;
|
|
4236
|
-
const nx2 = node.x + 160;
|
|
4392
|
+
const nx1 = node.editorOption.x;
|
|
4393
|
+
const nx2 = node.editorOption.x + 160;
|
|
4237
4394
|
const minX = Math.min(fromX, toX);
|
|
4238
4395
|
const maxX = Math.max(fromX, toX);
|
|
4239
4396
|
return nx2 > minX && nx1 < maxX;
|
|
4240
4397
|
}
|
|
4241
4398
|
doesLineCrossNodeY(y, node, tolerance = 6) {
|
|
4242
|
-
const top = node.y;
|
|
4243
|
-
const bottom = node.y + 80;
|
|
4399
|
+
const top = node.editorOption.y;
|
|
4400
|
+
const bottom = node.editorOption.y + 80;
|
|
4244
4401
|
return y > top + tolerance && y < bottom - tolerance;
|
|
4245
4402
|
}
|
|
4246
4403
|
isLaneClear(from, toX, routeY) {
|
|
4247
|
-
const x1 = from.node.x;
|
|
4248
|
-
const y1 = from.node.y + 40;
|
|
4404
|
+
const x1 = from.node.editorOption.x;
|
|
4405
|
+
const y1 = from.node.editorOption.y + 40;
|
|
4249
4406
|
const x2 = toX;
|
|
4250
4407
|
const y2 = routeY;
|
|
4251
4408
|
return !this.lstStage.some((n) => {
|
|
4252
|
-
if (n.
|
|
4409
|
+
if (n.WF_TemplateStage_Id === from.node.WF_TemplateStage_Id)
|
|
4253
4410
|
return false;
|
|
4254
4411
|
// node phải nằm giữa theo trục X
|
|
4255
4412
|
if (!this.isNodeBetweenX(x1, x2, n))
|
|
@@ -4259,7 +4416,7 @@ class WorkflowEditorComponent extends BaseComponent {
|
|
|
4259
4416
|
});
|
|
4260
4417
|
}
|
|
4261
4418
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WorkflowEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
4262
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: WorkflowEditorComponent, isStandalone: true, selector: "app-workflow-editor", inputs: { lstOrg: "lstOrg", lstTemplateType: "lstTemplateType", lstTemplatePrint: "lstTemplatePrint", template: "template", lstStage: "lstStage", lstAction: "lstAction" }, outputs: { onSave: "onSave" }, 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: "inputStageStatusElement", first: true, predicate: ["inputStageStatusElement"], descendants: true }, { propertyName: "inputActionTypeElement", first: true, predicate: ["inputActionTypeElement"], descendants: true }, { propertyName: "inputElement", first: true, predicate: ["inputElement"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div\n #canvasRef\n class=\"workflow-canvas\"\n [class.connecting]=\"!!connectingFrom\"\n [class.dragging-point]=\"!!draggingPoint\"\n [style.width.px]=\"CANVAS_WIDTH\"\n [style.height.px]=\"CANVAS_HEIGHT\"\n (mousedown)=\"onMouseDownCanvas($event)\"\n (mousemove)=\"onMouseMoveCanvas($event)\"\n (mouseup)=\"onMouseUpCanvas($event)\"\n (click)=\"onClickCanvas($event)\"\n>\n <!-- \n\n [style.width.px]=\"getCanvasWidth()\"\n [style.height.px]=\"getCanvasHeight()\" \n\n style=\"width: 100%; height: calc(100vh - 120px)\"\n \n -->\n\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 <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Template setting\" (click)=\"drawTemplateVisibel = true\">\n <nz-icon nzType=\"setting\"></nz-icon> T\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 nz-tooltip=\"Save\" (click)=\"save()\">\n <nz-icon nzType=\"save\"></nz-icon>\n </button>\n <button nz-button nzSize=\"small\" nz-tooltip=\"Add stage\" (click)=\"addStage()\">\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\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]=\"lstSelectedStageCode.size < 2\" (click)=\"alignLeft()\">\u27F8</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignCenter()\">\u2261</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignRight()\">\u27F9</button>\n\n <span class=\"divider\"></span>\n\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignTop()\">\u21D1</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignMiddle()\">\u2550</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignBottom()\">\u21D3</button>\n\n <span class=\"divider\"></span>\n\n <!-- DISTRIBUTE -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 3\" (click)=\"distributeHorizontal()\">\n \u21C4\n </button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 3\" (click)=\"distributeVertical()\">\n \u21C5\n </button>\n </div>\n\n <div\n class=\"canvas-content\"\n [class.panning]=\"isMoveMode\"\n [style.transform]=\"'translate(' + panX + 'px,' + panY + 'px)'\"\n >\n <!-- GRID -->\n <div *ngIf=\"wfcSetting.ShowGrid\" class=\"grid-layer\"></div>\n\n <!-- <div class=\"zoom-toolbar\">\n <button nz-button nzSize=\"small\" (click)=\"zoomOut()\">\u2212</button>\n <span>{{ zoom * 100 | number: \"1.0-0\" }}%</span>\n <button nz-button nzSize=\"small\" (click)=\"zoomIn()\">+</button>\n </div> -->\n\n <!-- SVG EDGES -->\n <svg #svg class=\"edges-layer\" width=\"100%\" height=\"100%\" preserveAspectRatio=\"none\">\n <g [attr.transform]=\"svgTransform\">\n <!-- DEFS -->\n <defs>\n <!-- glow effect -->\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 <!-- arrow markers -->\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\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\n <marker\n id=\"arrow-blue-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M10,0 L0,5 L10,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-red-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M10,0 L0,5 L10,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\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 <path\n class=\"edge\"\n [attr.id]=\"'edge-path-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-blue)\"\n [attr.marker-start]=\"e.allowBack ? 'url(#arrow-blue-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- text b\u00E1m theo line -->\n <!-- \n <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text> \n \n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text>\n -->\n\n <!-- text th\u1EB3ng n\u1EB1m ngang -->\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- EDGE \u0110ANG HOVER (LU\u00D4N TR\u00CAN C\u00D9NG) -->\n <ng-container *ngFor=\"let e of hoverEdges; let i = index\">\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\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 [attr.marker-start]=\"e.allowBack ? 'url(#arrow-red-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text>\n\n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text> -->\n\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- preview -->\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 <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 <!-- lstStage -->\n @for (n of lstStage; track $index) {\n @if (n.StageType == \"NODE\") {\n <nz-card\n #nodeEl\n class=\"workflow-node\"\n [attr.data-id]=\"n.Code\"\n [class.selected]=\"n == selectedStage || n == hoverStage || lstSelectedStageCode.has(n.Code)\"\n [style.left.px]=\"n.x\"\n [style.top.px]=\"n.y\"\n [class.connecting-source]=\"isConnectingFrom(n) || isDraggingFrom(n) || isSelectedNode(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\">{{ n.Code }}</div>\n\n <div>{{ n.Name }}</div>\n\n @if (!n.isReverse) {\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-left\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n } @else {\n <div class=\"connector connector-right reverse\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n <div class=\"connector connector-left reverse\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n }\n </nz-card>\n }\n <!-- START NODE -->\n @else if (n.StageType === \"START\") {\n <nz-card\n class=\"workflow-node workflow-node-start\"\n style=\"border: unset\"\n [style.left.px]=\"n.x\"\n [style.top.px]=\"n.y\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\"> </div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageCode.has(n.Code)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.isReverseLabel ? -83 : 1\"\n [nzColor]=\"'green'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right connector-start\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n </nz-card>\n }\n\n <!-- END NODE -->\n @else if (n.StageType === \"END\") {\n <nz-card\n class=\"workflow-node workflow-node-end\"\n style=\"border: unset\"\n [style.left.px]=\"n.x\"\n [style.top.px]=\"n.y\"\n [class.connecting-source]=\"isConnectingFrom(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\"> </div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageCode.has(n.Code)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.isReverseLabel ? 65 : -5\"\n [nzColor]=\"'red'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-end\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n </nz-card>\n }\n }\n\n <!-- POINTS -->\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, hoverAction!, $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<!-- TEMPLATE -->\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=\"setting\"></nz-icon> Template </ng-template>\n <ng-container *nzDrawerContent>\n <extend-input [label]=\"'Code'\" [(_ngModel)]=\"template.Code\"></extend-input>\n <extend-input [label]=\"'Name'\" [(_ngModel)]=\"template.Name\"></extend-input>\n <extend-select\n [label]=\"'Type'\"\n [lstItem]=\"lstTemplateType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.DocType\"\n ></extend-select>\n <extend-textarea [label]=\"'Desscription'\" [(_ngModel)]=\"template.Description\"></extend-textarea>\n <extend-select\n [label]=\"'Print template'\"\n [lstItem]=\"lstTemplatePrint\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.TemplatePrint\"\n ></extend-select>\n <extend-checkbox [label]=\"'Active'\" [(_ngModel)]=\"template.IsActive\"></extend-checkbox>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> Stage status</h3>\n\n @for (tag of template.lstStageStatus; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableStageStatus(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseStageStatus(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstStageStatus && template.lstStageStatus.length\" />\n\n @if (!inputStageStatusVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputStageStatus()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputStageStatusElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputStageStatusCode\"\n (keydown.enter)=\"inputStageStatusNameElement.select()\"\n />\n <input\n #inputStageStatusNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputStageStatusName\"\n (blur)=\"handleInputStageStatusConfirm()\"\n (keydown.enter)=\"handleInputStageStatusConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> Action type</h3>\n\n @for (tag of template.lstActionType; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableActionType(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseActionType(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionType && template.lstActionType.length\" />\n\n @if (!inputActionTypeVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputActionType()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputActionTypeElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputActionTypeCode\"\n (keydown.enter)=\"inputActionTypeNameElement.select()\"\n />\n <input\n #inputActionTypeNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputActionTypeName\"\n (blur)=\"handleInputActionTypeConfirm()\"\n (keydown.enter)=\"handleInputActionTypeConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> Action status</h3>\n\n @for (tag of template.lstActionStatus; track tag) {\n <nz-tag [nzMode]=\"checkRemoveableActionStatus(tag) ? 'closeable' : 'default'\" (nzOnClose)=\"handleClose(tag)\">\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionStatus && template.lstActionStatus.length\" />\n\n @if (!inputVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInput()\">\n <nz-icon nzType=\"plus\" />\n New Action status\n </nz-tag>\n } @else {\n <input\n #inputElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"+ New Action status\"\n [(ngModel)]=\"inputValue\"\n (blur)=\"handleInputConfirm()\"\n (keydown.enter)=\"handleInputConfirm()\"\n />\n }\n </ng-container>\n\n <ng-template #footerTplTemplate>\n <div nz-flex [nzGap]=\"6\">\n <button nz-button (click)=\"drawTemplateVisibel = false\">Close</button>\n <button nz-button nzDanger (click)=\"save()\">Save</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- STAGE -->\n<nz-drawer\n [nzTitle]=\"drawerTitleStage\"\n [nzPlacement]=\"selectedStage?.drawerPosition ? selectedStage?.drawerPosition : 'right'\"\n [nzVisible]=\"!!selectedStage\"\n [nzWidth]=\"750\"\n [nzClosable]=\"false\"\n [nzFooter]=\"footerTplNode\"\n (nzOnClose)=\"selectedStage = undefined\"\n>\n <ng-template #drawerTitleStage>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedStage) {\n @if (selectedStage.drawerPosition == \"left\") {\n <button nz-button nzSize=\"small\" nz-tooltip=\"To the right\" (click)=\"selectedStage.drawerPosition = 'right'\">\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n STAGE\n } @else {\n STAGE\n <button nz-button nzSize=\"small\" nz-tooltip=\"To the left\" (click)=\"selectedStage.drawerPosition = 'left'\">\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedStage\">\n <nz-radio-group [(ngModel)]=\"selectedStage.StageType\">\n <label nz-radio nzValue=\"START\" [nzDisabled]=\"selectedStage.StageType != 'START'\">START</label>\n <label nz-radio nzValue=\"NODE\" [nzDisabled]=\"selectedStage.StageType != 'NODE'\">NODE</label>\n <label nz-radio nzValue=\"END\" [nzDisabled]=\"selectedStage.StageType != 'END'\">END</label>\n </nz-radio-group>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"32\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Code'\"\n [layOutType]=\"'vertical'\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Code\"\n ></extend-input>\n\n <extend-textarea\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Name'\"\n [layOutType]=\"'vertical'\"\n [autoSize]=\"true\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Name\"\n ></extend-textarea>\n </div>\n\n <div nz-row [nzGutter]=\"32\">\n <extend-input-number\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Sequence'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedStage.SeqValue\"\n ></extend-input-number>\n\n <extend-select\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Org implement'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstOrg\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedStage.OrgImplCode\"\n ></extend-select>\n </div>\n\n @if ([\"START\", \"END\"].indexOf(selectedStage.StageType) < 0) {\n <extend-checkbox [label]=\"'Reverse'\" [labelSpan]=\"0\" [(_ngModel)]=\"selectedStage.isReverse\"></extend-checkbox>\n\n <extend-checkbox\n [label]=\"'Require user action'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.IsRequireUser\"\n ></extend-checkbox>\n } @else {\n <extend-checkbox\n [label]=\"'Reverse'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.isReverseLabel\"\n ></extend-checkbox>\n }\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\">\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> List Action</h3>\n <div nz-col>\n <button nz-button nzType=\"primary\" nzSize=\"small\" (click)=\"addAction()\">\n <nz-icon nzType=\"plus\"></nz-icon>\n </button>\n </div>\n </div>\n\n <nz-table\n nzSize=\"small\"\n [nzData]=\"selectedStage.lstAction || []\"\n [nzShowPagination]=\"false\"\n [nzNoResult]=\"' '\"\n >\n <thead>\n <tr [hidden]=\"true\">\n <th nzWidth=\"50px\"></th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n @for (action of selectedStage.lstAction; track $index) {\n <tr>\n <td>\n <nz-icon\n nzType=\"delete\"\n nzTheme=\"outline\"\n class=\"color-warn cursor-pointer icon-size-16\"\n (click)=\"$event.stopPropagation(); deleteAction(action)\"\n ></nz-icon>\n </td>\n <td (click)=\"hoverAction = action\">\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"action.ActionText\"\n (_ngModelChange)=\"onchangeActionText(action)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ToStage\"\n (_ngModelChange)=\"onchangeNextStage(action)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.NextStageStatus\"\n ></extend-select>\n </div>\n </td>\n </tr>\n }\n </tbody>\n </nz-table>\n\n <box [height]=\"16\"></box>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplNode>\n <div nz-flex [nzGap]=\"6\" [nzJustify]=\"selectedStage && selectedStage.drawerPosition == 'left' ? 'end' : 'start'\">\n <button nz-button (click)=\"selectedStage = undefined\">Close</button>\n <button\n *ngIf=\"selectedStage && ['START', 'END'].indexOf(selectedStage.StageType) < 0\"\n nz-button\n nzDanger\n (click)=\"deleteNode()\"\n >\n Delete\n </button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- EDGE -->\n<nz-drawer\n [nzTitle]=\"drawerTitleAction\"\n nzTitle=\"ACTION\"\n [nzPlacement]=\"selectedAction?.drawerPosition ? selectedAction?.drawerPosition : 'right'\"\n [nzClosable]=\"false\"\n [nzWidth]=\"750\"\n [nzVisible]=\"!!selectedAction\"\n [nzFooter]=\"footerTplAction\"\n (nzOnClose)=\"selectedAction = undefined\"\n>\n <ng-template #drawerTitleAction>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedAction) {\n @if (selectedAction.drawerPosition == \"left\") {\n <button nz-button nzSize=\"small\" nz-tooltip=\"To the right\" (click)=\"selectedAction.drawerPosition = 'right'\">\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n ACTION\n } @else {\n ACTION\n <button nz-button nzSize=\"small\" nz-tooltip=\"To the left\" (click)=\"selectedAction.drawerPosition = 'left'\">\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedAction\">\n <strong>{{ selectedAction.FromStage }} -> {{ selectedAction.ToStage }}</strong>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ToStage\"\n (_ngModelChange)=\"onchangeNextStage(selectedAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.NextStageStatus\"\n ></extend-select>\n </div>\n\n <!-- <box [height]=\"16\"></box> -->\n <nz-divider></nz-divider>\n\n <extend-checkbox\n [label]=\"'Allow back'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedAction.allowBack\"\n (_ngModelChange)=\"onchangeAllowBack(selectedAction)\"\n ></extend-checkbox>\n\n <box [height]=\"16\"></box>\n\n @if (selectedAction.allowBack) {\n <strong>{{ selectedAction.ToStage }} -> {{ selectedAction.FromStage }}</strong>\n\n @if (selectedBackAction) {\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedBackAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedBackAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ToStage\"\n (_ngModelChange)=\"onchangeNextStage(selectedBackAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.NextStageStatus\"\n ></extend-select>\n </div>\n }\n }\n </ng-container>\n </ng-container>\n <ng-template #footerTplAction>\n <div nz-flex [nzGap]=\"6\" [nzJustify]=\"selectedAction && selectedAction.drawerPosition == 'left' ? 'end' : 'start'\">\n <button nz-button (click)=\"selectedAction = undefined\">Close</button>\n <button nz-button nzDanger (click)=\"deleteAction(selectedAction!)\">Delete</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- setting editor -->\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> Editor </ng-template>\n <ng-container *nzDrawerContent>\n <div class=\"form-item-no-bottom\">\n <extend-checkbox [label]=\"'Show grid'\" [labelSpan]=\"0\" [(_ngModel)]=\"wfcSetting.ShowGrid\"></extend-checkbox>\n\n <box [height]=\"16\"></box>\n </div>\n </ng-container>\n</nz-drawer>\n", styles: ["@charset \"UTF-8\";.workflow-canvas{position:relative;width:100%;height:600px;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:10000px;height:10000px}.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 .title{font-weight:600;margin-bottom:6px}.workflow-node.connecting-source,.workflow-node.selected,.workflow-node:hover:not(.workflow-node-start,.workflow-node-end){outline:2px dashed #1890ff}.workflow-node-start{background-color:unset;display:flex;justify-content:right}.workflow-node-end{background-color:unset;display:flex}.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:-3px;background:green;box-shadow:0 0 0 3px #1890ff4d}.connector-end{width:16px;height:16px;left:-6px;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}.zoom-toolbar{position:absolute;top:8px;left:8px;z-index:10;display:flex;align-items:center;gap:6px;background:#fff;padding:4px 6px;border-radius:6px;box-shadow:0 2px 6px #00000026}.zoom-toolbar span{min-width:40px;text-align:center;font-size:12px}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}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NzCardModule }, { kind: "component", type: i3$1.NzCardComponent, selector: "nz-card", inputs: ["nzBordered", "nzLoading", "nzHoverable", "nzBodyStyle", "nzCover", "nzActions", "nzType", "nzSize", "nzTitle", "nzExtra"], exportAs: ["nzCard"] }, { kind: "ngmodule", type: NzDrawerModule }, { kind: "component", type: i4$1.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: i4$1.NzDrawerContentDirective, selector: "[nzDrawerContent]", exportAs: ["nzDrawerContent"] }, { kind: "ngmodule", type: NzTagModule }, { kind: "component", type: i5$2.NzTagComponent, selector: "nz-tag", inputs: ["nzMode", "nzColor", "nzChecked", "nzBordered"], outputs: ["nzOnClose", "nzCheckedChange"], exportAs: ["nzTag"] }, { kind: "ngmodule", type: NzRadioModule }, { kind: "component", type: i6$3.NzRadioComponent, selector: "[nz-radio],[nz-radio-button]", inputs: ["nzValue", "nzDisabled", "nzAutoFocus", "nz-radio-button"], exportAs: ["nzRadio"] }, { kind: "component", type: i6$3.NzRadioGroupComponent, selector: "nz-radio-group", inputs: ["nzDisabled", "nzButtonStyle", "nzSize", "nzName"], exportAs: ["nzRadioGroup"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i2.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: i8.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i9.ɵ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: i10.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }, { kind: "ngmodule", type: NzToolTipModule }, { kind: "directive", type: i11.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: ["layOutType", "label", "placeHolder", "labelAlign", "inputClass", "labelSpan", "allowClear", "disabled", "readOnly", "required", "noBottom", "selectModeType", "autocomplete", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "size", "lstItem", "displayField", "valueField", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange", "onclickClearIcon", "onenter"] }, { kind: "component", type: ExtendSelectComponent, selector: "extend-select", inputs: ["layOutType", "label", "placeHolder", "labelAlign", "labelSpan", "disabled", "required", "noBottom", "multiple", "showSelectAll", "maxTagCount", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "size", "lstItem", "displayField", "displayFields", "valueField", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange", "itemChange", "onFocus"] }, { kind: "component", type: ExtendCheckbox, selector: "extend-checkbox", inputs: ["label", "labelSpan", "disabled", "formData", "controlName", "valueType", "_ngModel"], outputs: ["_ngModelChange"] }, { kind: "component", type: ExtendTextArea, selector: "extend-textarea", inputs: ["layOutType", "label", "placeHolder", "labelAlign", "labelSpan", "inputSpan", "disabled", "required", "noBottom", "selectModeType", "inputClass", "minRows", "maxRows", "autoSize", "lstItem", "displayField", "valueField", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange"] }, { kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i6$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "ngmodule", type: NzGridModule }, { kind: "directive", type: i4.NzColDirective, selector: "[nz-col],nz-col,nz-form-control,nz-form-label", inputs: ["nzFlex", "nzSpan", "nzOrder", "nzOffset", "nzPush", "nzPull", "nzXs", "nzSm", "nzMd", "nzLg", "nzXl", "nzXXl"], exportAs: ["nzCol"] }, { kind: "directive", type: i4.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "ngmodule", type: NzFlexModule }, { kind: "directive", type: i14.NzFlexDirective, selector: "[nz-flex],nz-flex", inputs: ["nzVertical", "nzJustify", "nzAlign", "nzGap", "nzWrap", "nzFlex"], exportAs: ["nzFlex"] }, { kind: "component", type: ExtendInputNumber, selector: "extend-input-number", inputs: ["layOutType", "label", "placeHolder", "labelAlign", "labelSpan", "disabled", "required", "noBottom", "size", "min", "max", "precision", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "separatorType", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange"] }, { kind: "ngmodule", type: NzTableModule }, { kind: "component", type: i15.NzTableComponent, selector: "nz-table", inputs: ["nzTableLayout", "nzShowTotal", "nzItemRender", "nzTitle", "nzFooter", "nzNoResult", "nzPageSizeOptions", "nzVirtualItemSize", "nzVirtualMaxBufferPx", "nzVirtualMinBufferPx", "nzVirtualForTrackBy", "nzLoadingDelay", "nzPageIndex", "nzPageSize", "nzTotal", "nzWidthConfig", "nzData", "nzCustomColumn", "nzPaginationPosition", "nzScroll", "noDataVirtualHeight", "nzPaginationType", "nzFrontPagination", "nzTemplateMode", "nzShowPagination", "nzLoading", "nzOuterBordered", "nzLoadingIndicator", "nzBordered", "nzSize", "nzShowSizeChanger", "nzHideOnSinglePage", "nzShowQuickJumper", "nzSimple"], outputs: ["nzPageSizeChange", "nzPageIndexChange", "nzQueryParams", "nzCurrentPageDataChange", "nzCustomColumnChange"], exportAs: ["nzTable"] }, { kind: "directive", type: i15.NzTableCellDirective, selector: "th:not(.nz-disable-th):not([mat-cell]), td:not(.nz-disable-td):not([mat-cell])" }, { kind: "directive", type: i15.NzThMeasureDirective, selector: "th", inputs: ["nzWidth", "colspan", "colSpan", "rowspan", "rowSpan"] }, { kind: "component", type: i15.NzTheadComponent, selector: "thead:not(.ant-table-thead)", outputs: ["nzSortOrderChange"] }, { kind: "component", type: i15.NzTbodyComponent, selector: "tbody" }, { kind: "directive", type: i15.NzTrDirective, selector: "tr:not([mat-row]):not([mat-header-row]):not([nz-table-measure-row]):not([nzExpand]):not([nz-table-fixed-row])" }, { kind: "ngmodule", type: NzDividerModule }, { kind: "component", type: i16.NzDividerComponent, selector: "nz-divider", inputs: ["nzText", "nzType", "nzOrientation", "nzVariant", "nzDashed", "nzPlain"], exportAs: ["nzDivider"] }] });
|
|
4419
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.7", type: WorkflowEditorComponent, isStandalone: true, selector: "app-workflow-editor", inputs: { lstOrg: "lstOrg", lstRole: "lstRole" }, outputs: { onSave: "onSave", onDeleteStage: "onDeleteStage", onDeleteAction: "onDeleteAction" }, 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: "inputStageStatusElement", first: true, predicate: ["inputStageStatusElement"], descendants: true }, { propertyName: "inputActionTypeElement", first: true, predicate: ["inputActionTypeElement"], descendants: true }, { propertyName: "inputElement", first: true, predicate: ["inputElement"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div\n #canvasRef\n class=\"workflow-canvas\"\n [class.connecting]=\"!!connectingFrom\"\n [class.dragging-point]=\"!!draggingPoint\"\n [style.width.px]=\"CANVAS_WIDTH\"\n [style.height.px]=\"CANVAS_HEIGHT\"\n (mousedown)=\"onMouseDownCanvas($event)\"\n (mousemove)=\"onMouseMoveCanvas($event)\"\n (mouseup)=\"onMouseUpCanvas($event)\"\n (click)=\"onClickCanvas($event)\"\n>\n <!-- \n\n [style.width.px]=\"getCanvasWidth()\"\n [style.height.px]=\"getCanvasHeight()\" \n\n style=\"width: 100%; height: calc(100vh - 120px)\"\n \n -->\n\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 <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Template setting\" (click)=\"drawTemplateVisibel = true\">\n <nz-icon nzType=\"setting\"></nz-icon> T\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 nz-tooltip=\"Save\" (click)=\"save()\">\n <nz-icon nzType=\"save\"></nz-icon>\n </button>\n <button nz-button nzSize=\"small\" nz-tooltip=\"Add stage\" (click)=\"addStage()\">\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\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]=\"lstSelectedStageId.size < 2\" (click)=\"alignLeft()\">\u27F8</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignCenter()\">\u2261</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignRight()\">\u27F9</button>\n\n <span class=\"divider\"></span>\n\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignTop()\">\u21D1</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignMiddle()\">\u2550</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignBottom()\">\u21D3</button>\n\n <span class=\"divider\"></span>\n\n <!-- DISTRIBUTE -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 3\" (click)=\"distributeHorizontal()\">\n \u21C4\n </button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 3\" (click)=\"distributeVertical()\">\u21C5</button>\n </div>\n\n <div\n class=\"canvas-content\"\n [class.panning]=\"isMoveMode\"\n [style.transform]=\"'translate(' + panX + 'px,' + panY + 'px)'\"\n >\n <!-- GRID -->\n <div *ngIf=\"wfcSetting.ShowGrid\" class=\"grid-layer\"></div>\n\n <!-- <div class=\"zoom-toolbar\">\n <button nz-button nzSize=\"small\" (click)=\"zoomOut()\">\u2212</button>\n <span>{{ zoom * 100 | number: \"1.0-0\" }}%</span>\n <button nz-button nzSize=\"small\" (click)=\"zoomIn()\">+</button>\n </div> -->\n\n <!-- SVG EDGES -->\n <svg #svg class=\"edges-layer\" width=\"100%\" height=\"100%\" preserveAspectRatio=\"none\">\n <g [attr.transform]=\"svgTransform\">\n <!-- DEFS -->\n <defs>\n <!-- glow effect -->\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 <!-- arrow markers -->\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\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\n <marker\n id=\"arrow-blue-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M10,0 L0,5 L10,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-red-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M10,0 L0,5 L10,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\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 <path\n class=\"edge\"\n [attr.id]=\"'edge-path-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-blue)\"\n [attr.marker-start]=\"e.allowBack ? 'url(#arrow-blue-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- text b\u00E1m theo line -->\n <!-- \n <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text> \n \n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text>\n -->\n\n <!-- text th\u1EB3ng n\u1EB1m ngang -->\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- EDGE \u0110ANG HOVER (LU\u00D4N TR\u00CAN C\u00D9NG) -->\n <ng-container *ngFor=\"let e of hoverEdges; let i = index\">\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\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 [attr.marker-start]=\"e.allowBack ? 'url(#arrow-red-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text>\n\n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text> -->\n\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- preview -->\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 <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 <!-- lstStage -->\n @for (n of lstStage; track $index) {\n @if (n.StageType == \"NODE\") {\n <nz-card\n #nodeEl\n class=\"workflow-node\"\n [attr.data-id]=\"n.Code\"\n [class.selected]=\"n == selectedStage || n == hoverStage || lstSelectedStageId.has(n.WF_TemplateStage_Id)\"\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(); onClickStage(n)\"\n >\n <div class=\"title\">{{ n.Code }}</div>\n\n <div>{{ n.Name }}</div>\n\n @if (!n.editorOption.isReverse) {\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-left\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n } @else {\n <div class=\"connector connector-right reverse\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n <div class=\"connector connector-left reverse\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n }\n </nz-card>\n }\n <!-- START NODE -->\n @else if (n.StageType === \"START\") {\n <nz-card\n class=\"workflow-node workflow-node-start\"\n style=\"border: unset\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\"> </div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageId.has(n.WF_TemplateStage_Id)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.editorOption.isReverseLabel ? -83 : 1\"\n [nzColor]=\"'green'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right connector-start\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n </nz-card>\n }\n\n <!-- END NODE -->\n @else if (n.StageType === \"END\") {\n <nz-card\n class=\"workflow-node workflow-node-end\"\n style=\"border: unset\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\"> </div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageId.has(n.WF_TemplateStage_Id)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.editorOption.isReverseLabel ? 65 : -5\"\n [nzColor]=\"'red'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-end\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n </nz-card>\n }\n }\n\n <!-- POINTS -->\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, hoverAction!, $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<!-- drawer TEMPLATE -->\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=\"setting\"></nz-icon> Template </ng-template>\n <ng-container *nzDrawerContent>\n <extend-input [label]=\"'Code'\" [(_ngModel)]=\"template.Code\"></extend-input>\n <extend-input [label]=\"'Name'\" [(_ngModel)]=\"template.Name\"></extend-input>\n <extend-select\n [label]=\"'Type'\"\n [lstItem]=\"template.lstTemplateType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.DocType\"\n ></extend-select>\n <extend-textarea [label]=\"'Desscription'\" [(_ngModel)]=\"template.Description\"></extend-textarea>\n <extend-select\n [label]=\"'Print template'\"\n [lstItem]=\"template.lstTemplatePrint\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.TemplatePrint\"\n ></extend-select>\n <extend-checkbox [label]=\"'Active'\" [(_ngModel)]=\"template.IsActive\"></extend-checkbox>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> Stage</h3>\n\n @for (tag of lstStage; track tag) {\n <nz-tag (click)=\"hoverStage = tag\">\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> Stage status</h3>\n\n @for (tag of template.lstStageStatus; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableStageStatus(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseStageStatus(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstStageStatus && template.lstStageStatus.length\" />\n\n @if (!inputStageStatusVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputStageStatus()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputStageStatusElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputStageStatusCode\"\n (keydown.enter)=\"inputStageStatusNameElement.select()\"\n />\n <input\n #inputStageStatusNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputStageStatusName\"\n (blur)=\"handleInputStageStatusConfirm()\"\n (keydown.enter)=\"handleInputStageStatusConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> Action type</h3>\n\n @for (tag of template.lstActionType; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableActionType(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseActionType(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionType && template.lstActionType.length\" />\n\n @if (!inputActionTypeVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputActionType()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputActionTypeElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputActionTypeCode\"\n (keydown.enter)=\"inputActionTypeNameElement.select()\"\n />\n <input\n #inputActionTypeNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputActionTypeName\"\n (blur)=\"handleInputActionTypeConfirm()\"\n (keydown.enter)=\"handleInputActionTypeConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> Action status</h3>\n\n @for (tag of template.lstActionStatus; track tag) {\n <nz-tag [nzMode]=\"checkRemoveableActionStatus(tag) ? 'closeable' : 'default'\" (nzOnClose)=\"handleClose(tag)\">\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionStatus && template.lstActionStatus.length\" />\n\n @if (!inputVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInput()\">\n <nz-icon nzType=\"plus\" />\n New Action status\n </nz-tag>\n } @else {\n <input\n #inputElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"+ New Action status\"\n [(ngModel)]=\"inputValue\"\n (blur)=\"handleInputConfirm()\"\n (keydown.enter)=\"handleInputConfirm()\"\n />\n }\n </ng-container>\n\n <ng-template #footerTplTemplate>\n <div nz-flex [nzGap]=\"6\">\n <button nz-button (click)=\"drawTemplateVisibel = false\">Close</button>\n <button nz-button nzDanger (click)=\"save()\">Save</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- drawer STAGE -->\n<nz-drawer\n [nzTitle]=\"drawerTitleStage\"\n [nzPlacement]=\"selectedStage?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzVisible]=\"!!selectedStage\"\n [nzWidth]=\"750\"\n [nzClosable]=\"false\"\n [nzFooter]=\"footerTplNode\"\n (nzOnClose)=\"selectedStage = undefined\"\n>\n <ng-template #drawerTitleStage>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedStage && selectedStage.editorOption) {\n @if (selectedStage.editorOption.drawerPosition == \"left\") {\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the right\"\n (click)=\"selectedStage.editorOption.drawerPosition = 'right'\"\n >\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n STAGE\n } @else {\n STAGE\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the left\"\n (click)=\"selectedStage.editorOption.drawerPosition = 'left'\"\n >\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedStage\">\n <nz-radio-group [(ngModel)]=\"selectedStage.StageType\">\n <label nz-radio nzValue=\"START\" [nzDisabled]=\"selectedStage.StageType != 'START'\">START</label>\n <label nz-radio nzValue=\"NODE\" [nzDisabled]=\"selectedStage.StageType != 'NODE'\">NODE</label>\n <label nz-radio nzValue=\"END\" [nzDisabled]=\"selectedStage.StageType != 'END'\">END</label>\n </nz-radio-group>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"32\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Code'\"\n [layOutType]=\"'vertical'\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Code\"\n ></extend-input>\n\n <extend-textarea\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Name'\"\n [layOutType]=\"'vertical'\"\n [autoSize]=\"true\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Name\"\n ></extend-textarea>\n </div>\n\n <div nz-row [nzGutter]=\"32\" class=\"form-item-no-bottom\">\n <extend-input-number\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Sequence'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedStage.SeqValue\"\n ></extend-input-number>\n\n <extend-select\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Org implement'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstOrg\"\n [valueField]=\"'App_Org_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedStage.App_Org_Id\"\n ></extend-select>\n </div>\n\n <div nz-row [nzGutter]=\"32\" class=\"form-item-no-bottom\">\n <extend-input-number\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Number Day'\"\n [layOutType]=\"'vertical'\"\n [precision]=\"1\"\n [(_ngModel)]=\"selectedStage.NumberDay\"\n ></extend-input-number>\n </div>\n\n @if (selectedStage.editorOption) {\n @if ([\"START\", \"END\"].indexOf(selectedStage.StageType) < 0) {\n <extend-checkbox\n [label]=\"'Reverse'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.editorOption.isReverse\"\n ></extend-checkbox>\n\n <extend-checkbox\n [label]=\"'Require user action'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.IsRequireUser\"\n ></extend-checkbox>\n } @else {\n <extend-checkbox\n [label]=\"'Reverse'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.editorOption.isReverseLabel\"\n ></extend-checkbox>\n }\n }\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\">\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> List Action</h3>\n <div nz-col>\n <button nz-button nzType=\"primary\" nzSize=\"small\" (click)=\"addAction()\">\n <nz-icon nzType=\"plus\"></nz-icon>\n </button>\n </div>\n </div>\n\n <nz-table\n nzSize=\"small\"\n [nzData]=\"selectedStage.lstAction || []\"\n [nzShowPagination]=\"false\"\n [nzNoResult]=\"' '\"\n >\n <thead>\n <tr [hidden]=\"true\">\n <th nzWidth=\"50px\"></th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n @for (action of selectedStage.lstAction; track $index) {\n <tr>\n <td>\n <nz-icon\n nzType=\"delete\"\n nzTheme=\"outline\"\n class=\"color-warn cursor-pointer icon-size-16\"\n (click)=\"$event.stopPropagation(); deleteAction(action)\"\n ></nz-icon>\n </td>\n <td (click)=\"hoverAction = action\">\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"action.ActionText\"\n (_ngModelChange)=\"onchangeActionText(action)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'WF_TemplateStage_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.To_WF_TemplateStage_Id\"\n (_ngModelChange)=\"onchangeNextStage(action)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.NextStageStatus\"\n ></extend-select>\n </div>\n <box [height]=\"8\"></box>\n <div nz-row><strong>Role</strong></div>\n <div nz-row>\n <extend-select\n nz-col\n nzSpan=\"24\"\n [size]=\"'small'\"\n [lstItem]=\"lstRole\"\n [valueField]=\"'App_Role_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [multiple]=\"true\"\n [(_ngModel)]=\"action._lstRoleId\"\n (_ngModelChange)=\"onselectedRoleEmail(action)\"\n ></extend-select>\n </div>\n <box [height]=\"8\"></box>\n <div nz-row>\n <strong>Email action</strong>\n </div>\n <div nz-row>\n <extend-select\n nz-col\n nzSpan=\"24\"\n [size]=\"'small'\"\n [lstItem]=\"lstEmailAction\"\n [valueField]=\"'ID'\"\n [displayField]=\"'Name'\"\n [multiple]=\"true\"\n [(_ngModel)]=\"action._lstEmailActionId\"\n (_ngModelChange)=\"onselectedRoleEmail(action)\"\n ></extend-select>\n </div>\n </td>\n </tr>\n }\n </tbody>\n </nz-table>\n\n <box [height]=\"16\"></box>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplNode>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"\n selectedStage && selectedStage.editorOption && selectedStage.editorOption.drawerPosition == 'left'\n ? 'start'\n : 'end'\n \"\n >\n <button nz-button nzDanger nzDanger (click)=\"save()\">Save</button>\n <button nz-button (click)=\"selectedStage = undefined\">Close</button>\n <button\n *ngIf=\"selectedStage && ['START', 'END'].indexOf(selectedStage.StageType) < 0\"\n nz-button\n nzDanger\n (click)=\"deleteStage()\"\n >\n Delete\n </button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- drawer ACTION -->\n<nz-drawer\n [nzTitle]=\"drawerTitleAction\"\n nzTitle=\"ACTION\"\n [nzPlacement]=\"selectedAction?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzClosable]=\"false\"\n [nzWidth]=\"750\"\n [nzVisible]=\"!!selectedAction\"\n [nzFooter]=\"footerTplAction\"\n (nzOnClose)=\"selectedAction = undefined\"\n>\n <ng-template #drawerTitleAction>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedAction && selectedAction.editorOption) {\n @if (selectedAction.editorOption.drawerPosition == \"left\") {\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the right\"\n (click)=\"selectedAction.editorOption.drawerPosition = 'right'\"\n >\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n ACTION\n } @else {\n ACTION\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the left\"\n (click)=\"selectedAction.editorOption.drawerPosition = 'left'\"\n >\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedAction\">\n <strong>{{ selectedAction.FromStageCode }} -> {{ selectedAction.ToStageCode }}</strong>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'WF_TemplateStage_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.To_WF_TemplateStage_Id\"\n (_ngModelChange)=\"onchangeNextStage(selectedAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.NextStageStatus\"\n ></extend-select>\n </div>\n\n <!-- <box [height]=\"16\"></box> -->\n <nz-divider></nz-divider>\n\n <extend-checkbox\n [label]=\"'Allow back'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedAction.allowBack\"\n (_ngModelChange)=\"onchangeAllowBack(selectedAction)\"\n ></extend-checkbox>\n\n <box [height]=\"16\"></box>\n\n @if (selectedAction.allowBack) {\n <strong>{{ selectedAction.ToStageCode }} -> {{ selectedAction.FromStageCode }}</strong>\n\n @if (selectedBackAction) {\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedBackAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedBackAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'WF_TemplateStage_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.To_WF_TemplateStage_Id\"\n (_ngModelChange)=\"onchangeNextStage(selectedBackAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.NextStageStatus\"\n ></extend-select>\n </div>\n }\n }\n </ng-container>\n </ng-container>\n <ng-template #footerTplAction>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedAction && selectedAction.editorOption.drawerPosition == 'left' ? 'start' : 'end'\"\n >\n <button nz-button nzDanger nzDanger (click)=\"save()\">Save</button>\n <button nz-button (click)=\"selectedAction = undefined\">Close</button>\n <button nz-button nzDanger (click)=\"deleteAction(selectedAction!)\">Delete</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- setting editor -->\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> Editor </ng-template>\n <ng-container *nzDrawerContent>\n <div class=\"form-item-no-bottom\">\n <extend-checkbox [label]=\"'Show grid'\" [labelSpan]=\"0\" [(_ngModel)]=\"wfcSetting.ShowGrid\"></extend-checkbox>\n\n <box [height]=\"16\"></box>\n </div>\n </ng-container>\n</nz-drawer>\n", styles: ["@charset \"UTF-8\";.workflow-canvas{position:relative;width:100%;height:600px;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:10000px;height:10000px}.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 .title{font-weight:600;margin-bottom:6px}.workflow-node.connecting-source,.workflow-node.selected,.workflow-node:hover:not(.workflow-node-start,.workflow-node-end){outline:2px dashed #1890ff}.workflow-node-start{background-color:unset;display:flex;justify-content:right}.workflow-node-end{background-color:unset;display:flex}.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:-3px;background:green;box-shadow:0 0 0 3px #1890ff4d}.connector-end{width:16px;height:16px;left:-6px;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}.zoom-toolbar{position:absolute;top:8px;left:8px;z-index:10;display:flex;align-items:center;gap:6px;background:#fff;padding:4px 6px;border-radius:6px;box-shadow:0 2px 6px #00000026}.zoom-toolbar span{min-width:40px;text-align:center;font-size:12px}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}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NzCardModule }, { kind: "component", type: i3$1.NzCardComponent, selector: "nz-card", inputs: ["nzBordered", "nzLoading", "nzHoverable", "nzBodyStyle", "nzCover", "nzActions", "nzType", "nzSize", "nzTitle", "nzExtra"], exportAs: ["nzCard"] }, { kind: "ngmodule", type: NzDrawerModule }, { kind: "component", type: i4$1.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: i4$1.NzDrawerContentDirective, selector: "[nzDrawerContent]", exportAs: ["nzDrawerContent"] }, { kind: "ngmodule", type: NzTagModule }, { kind: "component", type: i5$2.NzTagComponent, selector: "nz-tag", inputs: ["nzMode", "nzColor", "nzChecked", "nzBordered"], outputs: ["nzOnClose", "nzCheckedChange"], exportAs: ["nzTag"] }, { kind: "ngmodule", type: NzRadioModule }, { kind: "component", type: i6$3.NzRadioComponent, selector: "[nz-radio],[nz-radio-button]", inputs: ["nzValue", "nzDisabled", "nzAutoFocus", "nz-radio-button"], exportAs: ["nzRadio"] }, { kind: "component", type: i6$3.NzRadioGroupComponent, selector: "nz-radio-group", inputs: ["nzDisabled", "nzButtonStyle", "nzSize", "nzName"], exportAs: ["nzRadioGroup"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i2.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: i8.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i9.ɵ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: i10.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }, { kind: "ngmodule", type: NzToolTipModule }, { kind: "directive", type: i11.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: ["layOutType", "label", "placeHolder", "labelAlign", "inputClass", "labelSpan", "allowClear", "disabled", "readOnly", "required", "noBottom", "selectModeType", "autocomplete", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "size", "lstItem", "displayField", "valueField", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange", "onclickClearIcon", "onenter"] }, { kind: "component", type: ExtendSelectComponent, selector: "extend-select", inputs: ["layOutType", "label", "placeHolder", "labelAlign", "labelSpan", "disabled", "required", "noBottom", "multiple", "showSelectAll", "maxTagCount", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "size", "lstItem", "displayField", "displayFields", "valueField", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange", "itemChange", "onFocus"] }, { kind: "component", type: ExtendCheckbox, selector: "extend-checkbox", inputs: ["label", "labelSpan", "disabled", "formData", "controlName", "valueType", "_ngModel"], outputs: ["_ngModelChange"] }, { kind: "component", type: ExtendTextArea, selector: "extend-textarea", inputs: ["layOutType", "label", "placeHolder", "labelAlign", "labelSpan", "inputSpan", "disabled", "required", "noBottom", "selectModeType", "inputClass", "minRows", "maxRows", "autoSize", "lstItem", "displayField", "valueField", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange"] }, { kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i6$1.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "ngmodule", type: NzGridModule }, { kind: "directive", type: i4.NzColDirective, selector: "[nz-col],nz-col,nz-form-control,nz-form-label", inputs: ["nzFlex", "nzSpan", "nzOrder", "nzOffset", "nzPush", "nzPull", "nzXs", "nzSm", "nzMd", "nzLg", "nzXl", "nzXXl"], exportAs: ["nzCol"] }, { kind: "directive", type: i4.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "ngmodule", type: NzFlexModule }, { kind: "directive", type: i14.NzFlexDirective, selector: "[nz-flex],nz-flex", inputs: ["nzVertical", "nzJustify", "nzAlign", "nzGap", "nzWrap", "nzFlex"], exportAs: ["nzFlex"] }, { kind: "component", type: ExtendInputNumber, selector: "extend-input-number", inputs: ["layOutType", "label", "placeHolder", "labelAlign", "labelSpan", "disabled", "required", "noBottom", "size", "min", "max", "precision", "inputWidth", "inputHeight", "borderBottomOnly", "displayInline", "separatorType", "formData", "controlName", "_ngModel"], outputs: ["_ngModelChange"] }, { kind: "ngmodule", type: NzTableModule }, { kind: "component", type: i15.NzTableComponent, selector: "nz-table", inputs: ["nzTableLayout", "nzShowTotal", "nzItemRender", "nzTitle", "nzFooter", "nzNoResult", "nzPageSizeOptions", "nzVirtualItemSize", "nzVirtualMaxBufferPx", "nzVirtualMinBufferPx", "nzVirtualForTrackBy", "nzLoadingDelay", "nzPageIndex", "nzPageSize", "nzTotal", "nzWidthConfig", "nzData", "nzCustomColumn", "nzPaginationPosition", "nzScroll", "noDataVirtualHeight", "nzPaginationType", "nzFrontPagination", "nzTemplateMode", "nzShowPagination", "nzLoading", "nzOuterBordered", "nzLoadingIndicator", "nzBordered", "nzSize", "nzShowSizeChanger", "nzHideOnSinglePage", "nzShowQuickJumper", "nzSimple"], outputs: ["nzPageSizeChange", "nzPageIndexChange", "nzQueryParams", "nzCurrentPageDataChange", "nzCustomColumnChange"], exportAs: ["nzTable"] }, { kind: "directive", type: i15.NzTableCellDirective, selector: "th:not(.nz-disable-th):not([mat-cell]), td:not(.nz-disable-td):not([mat-cell])" }, { kind: "directive", type: i15.NzThMeasureDirective, selector: "th", inputs: ["nzWidth", "colspan", "colSpan", "rowspan", "rowSpan"] }, { kind: "component", type: i15.NzTheadComponent, selector: "thead:not(.ant-table-thead)", outputs: ["nzSortOrderChange"] }, { kind: "component", type: i15.NzTbodyComponent, selector: "tbody" }, { kind: "directive", type: i15.NzTrDirective, selector: "tr:not([mat-row]):not([mat-header-row]):not([nz-table-measure-row]):not([nzExpand]):not([nz-table-fixed-row])" }, { kind: "ngmodule", type: NzDividerModule }, { kind: "component", type: i16.NzDividerComponent, selector: "nz-divider", inputs: ["nzText", "nzType", "nzOrientation", "nzVariant", "nzDashed", "nzPlain"], exportAs: ["nzDivider"] }] });
|
|
4263
4420
|
}
|
|
4264
4421
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: WorkflowEditorComponent, decorators: [{
|
|
4265
4422
|
type: Component,
|
|
@@ -4284,22 +4441,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImpor
|
|
|
4284
4441
|
ExtendInputNumber,
|
|
4285
4442
|
NzTableModule,
|
|
4286
4443
|
NzDividerModule,
|
|
4287
|
-
], template: "<div\n #canvasRef\n class=\"workflow-canvas\"\n [class.connecting]=\"!!connectingFrom\"\n [class.dragging-point]=\"!!draggingPoint\"\n [style.width.px]=\"CANVAS_WIDTH\"\n [style.height.px]=\"CANVAS_HEIGHT\"\n (mousedown)=\"onMouseDownCanvas($event)\"\n (mousemove)=\"onMouseMoveCanvas($event)\"\n (mouseup)=\"onMouseUpCanvas($event)\"\n (click)=\"onClickCanvas($event)\"\n>\n <!-- \n\n [style.width.px]=\"getCanvasWidth()\"\n [style.height.px]=\"getCanvasHeight()\" \n\n style=\"width: 100%; height: calc(100vh - 120px)\"\n \n -->\n\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 <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Template setting\" (click)=\"drawTemplateVisibel = true\">\n <nz-icon nzType=\"setting\"></nz-icon> T\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 nz-tooltip=\"Save\" (click)=\"save()\">\n <nz-icon nzType=\"save\"></nz-icon>\n </button>\n <button nz-button nzSize=\"small\" nz-tooltip=\"Add stage\" (click)=\"addStage()\">\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\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]=\"lstSelectedStageCode.size < 2\" (click)=\"alignLeft()\">\u27F8</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignCenter()\">\u2261</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignRight()\">\u27F9</button>\n\n <span class=\"divider\"></span>\n\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignTop()\">\u21D1</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignMiddle()\">\u2550</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 2\" (click)=\"alignBottom()\">\u21D3</button>\n\n <span class=\"divider\"></span>\n\n <!-- DISTRIBUTE -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 3\" (click)=\"distributeHorizontal()\">\n \u21C4\n </button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageCode.size < 3\" (click)=\"distributeVertical()\">\n \u21C5\n </button>\n </div>\n\n <div\n class=\"canvas-content\"\n [class.panning]=\"isMoveMode\"\n [style.transform]=\"'translate(' + panX + 'px,' + panY + 'px)'\"\n >\n <!-- GRID -->\n <div *ngIf=\"wfcSetting.ShowGrid\" class=\"grid-layer\"></div>\n\n <!-- <div class=\"zoom-toolbar\">\n <button nz-button nzSize=\"small\" (click)=\"zoomOut()\">\u2212</button>\n <span>{{ zoom * 100 | number: \"1.0-0\" }}%</span>\n <button nz-button nzSize=\"small\" (click)=\"zoomIn()\">+</button>\n </div> -->\n\n <!-- SVG EDGES -->\n <svg #svg class=\"edges-layer\" width=\"100%\" height=\"100%\" preserveAspectRatio=\"none\">\n <g [attr.transform]=\"svgTransform\">\n <!-- DEFS -->\n <defs>\n <!-- glow effect -->\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 <!-- arrow markers -->\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\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\n <marker\n id=\"arrow-blue-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M10,0 L0,5 L10,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-red-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M10,0 L0,5 L10,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\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 <path\n class=\"edge\"\n [attr.id]=\"'edge-path-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-blue)\"\n [attr.marker-start]=\"e.allowBack ? 'url(#arrow-blue-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- text b\u00E1m theo line -->\n <!-- \n <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text> \n \n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text>\n -->\n\n <!-- text th\u1EB3ng n\u1EB1m ngang -->\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- EDGE \u0110ANG HOVER (LU\u00D4N TR\u00CAN C\u00D9NG) -->\n <ng-container *ngFor=\"let e of hoverEdges; let i = index\">\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\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 [attr.marker-start]=\"e.allowBack ? 'url(#arrow-red-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text>\n\n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text> -->\n\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- preview -->\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 <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 <!-- lstStage -->\n @for (n of lstStage; track $index) {\n @if (n.StageType == \"NODE\") {\n <nz-card\n #nodeEl\n class=\"workflow-node\"\n [attr.data-id]=\"n.Code\"\n [class.selected]=\"n == selectedStage || n == hoverStage || lstSelectedStageCode.has(n.Code)\"\n [style.left.px]=\"n.x\"\n [style.top.px]=\"n.y\"\n [class.connecting-source]=\"isConnectingFrom(n) || isDraggingFrom(n) || isSelectedNode(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\">{{ n.Code }}</div>\n\n <div>{{ n.Name }}</div>\n\n @if (!n.isReverse) {\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-left\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n } @else {\n <div class=\"connector connector-right reverse\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n <div class=\"connector connector-left reverse\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n }\n </nz-card>\n }\n <!-- START NODE -->\n @else if (n.StageType === \"START\") {\n <nz-card\n class=\"workflow-node workflow-node-start\"\n style=\"border: unset\"\n [style.left.px]=\"n.x\"\n [style.top.px]=\"n.y\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\"> </div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageCode.has(n.Code)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.isReverseLabel ? -83 : 1\"\n [nzColor]=\"'green'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right connector-start\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n </nz-card>\n }\n\n <!-- END NODE -->\n @else if (n.StageType === \"END\") {\n <nz-card\n class=\"workflow-node workflow-node-end\"\n style=\"border: unset\"\n [style.left.px]=\"n.x\"\n [style.top.px]=\"n.y\"\n [class.connecting-source]=\"isConnectingFrom(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\"> </div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageCode.has(n.Code)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.isReverseLabel ? 65 : -5\"\n [nzColor]=\"'red'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-end\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n </nz-card>\n }\n }\n\n <!-- POINTS -->\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, hoverAction!, $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<!-- TEMPLATE -->\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=\"setting\"></nz-icon> Template </ng-template>\n <ng-container *nzDrawerContent>\n <extend-input [label]=\"'Code'\" [(_ngModel)]=\"template.Code\"></extend-input>\n <extend-input [label]=\"'Name'\" [(_ngModel)]=\"template.Name\"></extend-input>\n <extend-select\n [label]=\"'Type'\"\n [lstItem]=\"lstTemplateType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.DocType\"\n ></extend-select>\n <extend-textarea [label]=\"'Desscription'\" [(_ngModel)]=\"template.Description\"></extend-textarea>\n <extend-select\n [label]=\"'Print template'\"\n [lstItem]=\"lstTemplatePrint\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.TemplatePrint\"\n ></extend-select>\n <extend-checkbox [label]=\"'Active'\" [(_ngModel)]=\"template.IsActive\"></extend-checkbox>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> Stage status</h3>\n\n @for (tag of template.lstStageStatus; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableStageStatus(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseStageStatus(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstStageStatus && template.lstStageStatus.length\" />\n\n @if (!inputStageStatusVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputStageStatus()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputStageStatusElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputStageStatusCode\"\n (keydown.enter)=\"inputStageStatusNameElement.select()\"\n />\n <input\n #inputStageStatusNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputStageStatusName\"\n (blur)=\"handleInputStageStatusConfirm()\"\n (keydown.enter)=\"handleInputStageStatusConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> Action type</h3>\n\n @for (tag of template.lstActionType; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableActionType(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseActionType(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionType && template.lstActionType.length\" />\n\n @if (!inputActionTypeVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputActionType()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputActionTypeElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputActionTypeCode\"\n (keydown.enter)=\"inputActionTypeNameElement.select()\"\n />\n <input\n #inputActionTypeNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputActionTypeName\"\n (blur)=\"handleInputActionTypeConfirm()\"\n (keydown.enter)=\"handleInputActionTypeConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> Action status</h3>\n\n @for (tag of template.lstActionStatus; track tag) {\n <nz-tag [nzMode]=\"checkRemoveableActionStatus(tag) ? 'closeable' : 'default'\" (nzOnClose)=\"handleClose(tag)\">\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionStatus && template.lstActionStatus.length\" />\n\n @if (!inputVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInput()\">\n <nz-icon nzType=\"plus\" />\n New Action status\n </nz-tag>\n } @else {\n <input\n #inputElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"+ New Action status\"\n [(ngModel)]=\"inputValue\"\n (blur)=\"handleInputConfirm()\"\n (keydown.enter)=\"handleInputConfirm()\"\n />\n }\n </ng-container>\n\n <ng-template #footerTplTemplate>\n <div nz-flex [nzGap]=\"6\">\n <button nz-button (click)=\"drawTemplateVisibel = false\">Close</button>\n <button nz-button nzDanger (click)=\"save()\">Save</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- STAGE -->\n<nz-drawer\n [nzTitle]=\"drawerTitleStage\"\n [nzPlacement]=\"selectedStage?.drawerPosition ? selectedStage?.drawerPosition : 'right'\"\n [nzVisible]=\"!!selectedStage\"\n [nzWidth]=\"750\"\n [nzClosable]=\"false\"\n [nzFooter]=\"footerTplNode\"\n (nzOnClose)=\"selectedStage = undefined\"\n>\n <ng-template #drawerTitleStage>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedStage) {\n @if (selectedStage.drawerPosition == \"left\") {\n <button nz-button nzSize=\"small\" nz-tooltip=\"To the right\" (click)=\"selectedStage.drawerPosition = 'right'\">\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n STAGE\n } @else {\n STAGE\n <button nz-button nzSize=\"small\" nz-tooltip=\"To the left\" (click)=\"selectedStage.drawerPosition = 'left'\">\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedStage\">\n <nz-radio-group [(ngModel)]=\"selectedStage.StageType\">\n <label nz-radio nzValue=\"START\" [nzDisabled]=\"selectedStage.StageType != 'START'\">START</label>\n <label nz-radio nzValue=\"NODE\" [nzDisabled]=\"selectedStage.StageType != 'NODE'\">NODE</label>\n <label nz-radio nzValue=\"END\" [nzDisabled]=\"selectedStage.StageType != 'END'\">END</label>\n </nz-radio-group>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"32\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Code'\"\n [layOutType]=\"'vertical'\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Code\"\n ></extend-input>\n\n <extend-textarea\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Name'\"\n [layOutType]=\"'vertical'\"\n [autoSize]=\"true\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Name\"\n ></extend-textarea>\n </div>\n\n <div nz-row [nzGutter]=\"32\">\n <extend-input-number\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Sequence'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedStage.SeqValue\"\n ></extend-input-number>\n\n <extend-select\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Org implement'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstOrg\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedStage.OrgImplCode\"\n ></extend-select>\n </div>\n\n @if ([\"START\", \"END\"].indexOf(selectedStage.StageType) < 0) {\n <extend-checkbox [label]=\"'Reverse'\" [labelSpan]=\"0\" [(_ngModel)]=\"selectedStage.isReverse\"></extend-checkbox>\n\n <extend-checkbox\n [label]=\"'Require user action'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.IsRequireUser\"\n ></extend-checkbox>\n } @else {\n <extend-checkbox\n [label]=\"'Reverse'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.isReverseLabel\"\n ></extend-checkbox>\n }\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\">\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> List Action</h3>\n <div nz-col>\n <button nz-button nzType=\"primary\" nzSize=\"small\" (click)=\"addAction()\">\n <nz-icon nzType=\"plus\"></nz-icon>\n </button>\n </div>\n </div>\n\n <nz-table\n nzSize=\"small\"\n [nzData]=\"selectedStage.lstAction || []\"\n [nzShowPagination]=\"false\"\n [nzNoResult]=\"' '\"\n >\n <thead>\n <tr [hidden]=\"true\">\n <th nzWidth=\"50px\"></th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n @for (action of selectedStage.lstAction; track $index) {\n <tr>\n <td>\n <nz-icon\n nzType=\"delete\"\n nzTheme=\"outline\"\n class=\"color-warn cursor-pointer icon-size-16\"\n (click)=\"$event.stopPropagation(); deleteAction(action)\"\n ></nz-icon>\n </td>\n <td (click)=\"hoverAction = action\">\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"action.ActionText\"\n (_ngModelChange)=\"onchangeActionText(action)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ToStage\"\n (_ngModelChange)=\"onchangeNextStage(action)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.NextStageStatus\"\n ></extend-select>\n </div>\n </td>\n </tr>\n }\n </tbody>\n </nz-table>\n\n <box [height]=\"16\"></box>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplNode>\n <div nz-flex [nzGap]=\"6\" [nzJustify]=\"selectedStage && selectedStage.drawerPosition == 'left' ? 'end' : 'start'\">\n <button nz-button (click)=\"selectedStage = undefined\">Close</button>\n <button\n *ngIf=\"selectedStage && ['START', 'END'].indexOf(selectedStage.StageType) < 0\"\n nz-button\n nzDanger\n (click)=\"deleteNode()\"\n >\n Delete\n </button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- EDGE -->\n<nz-drawer\n [nzTitle]=\"drawerTitleAction\"\n nzTitle=\"ACTION\"\n [nzPlacement]=\"selectedAction?.drawerPosition ? selectedAction?.drawerPosition : 'right'\"\n [nzClosable]=\"false\"\n [nzWidth]=\"750\"\n [nzVisible]=\"!!selectedAction\"\n [nzFooter]=\"footerTplAction\"\n (nzOnClose)=\"selectedAction = undefined\"\n>\n <ng-template #drawerTitleAction>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedAction) {\n @if (selectedAction.drawerPosition == \"left\") {\n <button nz-button nzSize=\"small\" nz-tooltip=\"To the right\" (click)=\"selectedAction.drawerPosition = 'right'\">\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n ACTION\n } @else {\n ACTION\n <button nz-button nzSize=\"small\" nz-tooltip=\"To the left\" (click)=\"selectedAction.drawerPosition = 'left'\">\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedAction\">\n <strong>{{ selectedAction.FromStage }} -> {{ selectedAction.ToStage }}</strong>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ToStage\"\n (_ngModelChange)=\"onchangeNextStage(selectedAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.NextStageStatus\"\n ></extend-select>\n </div>\n\n <!-- <box [height]=\"16\"></box> -->\n <nz-divider></nz-divider>\n\n <extend-checkbox\n [label]=\"'Allow back'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedAction.allowBack\"\n (_ngModelChange)=\"onchangeAllowBack(selectedAction)\"\n ></extend-checkbox>\n\n <box [height]=\"16\"></box>\n\n @if (selectedAction.allowBack) {\n <strong>{{ selectedAction.ToStage }} -> {{ selectedAction.FromStage }}</strong>\n\n @if (selectedBackAction) {\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedBackAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedBackAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ToStage\"\n (_ngModelChange)=\"onchangeNextStage(selectedBackAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.NextStageStatus\"\n ></extend-select>\n </div>\n }\n }\n </ng-container>\n </ng-container>\n <ng-template #footerTplAction>\n <div nz-flex [nzGap]=\"6\" [nzJustify]=\"selectedAction && selectedAction.drawerPosition == 'left' ? 'end' : 'start'\">\n <button nz-button (click)=\"selectedAction = undefined\">Close</button>\n <button nz-button nzDanger (click)=\"deleteAction(selectedAction!)\">Delete</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- setting editor -->\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> Editor </ng-template>\n <ng-container *nzDrawerContent>\n <div class=\"form-item-no-bottom\">\n <extend-checkbox [label]=\"'Show grid'\" [labelSpan]=\"0\" [(_ngModel)]=\"wfcSetting.ShowGrid\"></extend-checkbox>\n\n <box [height]=\"16\"></box>\n </div>\n </ng-container>\n</nz-drawer>\n", styles: ["@charset \"UTF-8\";.workflow-canvas{position:relative;width:100%;height:600px;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:10000px;height:10000px}.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 .title{font-weight:600;margin-bottom:6px}.workflow-node.connecting-source,.workflow-node.selected,.workflow-node:hover:not(.workflow-node-start,.workflow-node-end){outline:2px dashed #1890ff}.workflow-node-start{background-color:unset;display:flex;justify-content:right}.workflow-node-end{background-color:unset;display:flex}.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:-3px;background:green;box-shadow:0 0 0 3px #1890ff4d}.connector-end{width:16px;height:16px;left:-6px;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}.zoom-toolbar{position:absolute;top:8px;left:8px;z-index:10;display:flex;align-items:center;gap:6px;background:#fff;padding:4px 6px;border-radius:6px;box-shadow:0 2px 6px #00000026}.zoom-toolbar span{min-width:40px;text-align:center;font-size:12px}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}\n"] }]
|
|
4444
|
+
], template: "<div\n #canvasRef\n class=\"workflow-canvas\"\n [class.connecting]=\"!!connectingFrom\"\n [class.dragging-point]=\"!!draggingPoint\"\n [style.width.px]=\"CANVAS_WIDTH\"\n [style.height.px]=\"CANVAS_HEIGHT\"\n (mousedown)=\"onMouseDownCanvas($event)\"\n (mousemove)=\"onMouseMoveCanvas($event)\"\n (mouseup)=\"onMouseUpCanvas($event)\"\n (click)=\"onClickCanvas($event)\"\n>\n <!-- \n\n [style.width.px]=\"getCanvasWidth()\"\n [style.height.px]=\"getCanvasHeight()\" \n\n style=\"width: 100%; height: calc(100vh - 120px)\"\n \n -->\n\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 <box [width]=\"1\"></box>\n <span class=\"divider\"></span>\n <box [width]=\"1\"></box>\n\n <button nz-button nzSize=\"small\" nz-tooltip=\"Template setting\" (click)=\"drawTemplateVisibel = true\">\n <nz-icon nzType=\"setting\"></nz-icon> T\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 nz-tooltip=\"Save\" (click)=\"save()\">\n <nz-icon nzType=\"save\"></nz-icon>\n </button>\n <button nz-button nzSize=\"small\" nz-tooltip=\"Add stage\" (click)=\"addStage()\">\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\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]=\"lstSelectedStageId.size < 2\" (click)=\"alignLeft()\">\u27F8</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignCenter()\">\u2261</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignRight()\">\u27F9</button>\n\n <span class=\"divider\"></span>\n\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignTop()\">\u21D1</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignMiddle()\">\u2550</button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 2\" (click)=\"alignBottom()\">\u21D3</button>\n\n <span class=\"divider\"></span>\n\n <!-- DISTRIBUTE -->\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 3\" (click)=\"distributeHorizontal()\">\n \u21C4\n </button>\n <button nz-button nzSize=\"small\" [disabled]=\"lstSelectedStageId.size < 3\" (click)=\"distributeVertical()\">\u21C5</button>\n </div>\n\n <div\n class=\"canvas-content\"\n [class.panning]=\"isMoveMode\"\n [style.transform]=\"'translate(' + panX + 'px,' + panY + 'px)'\"\n >\n <!-- GRID -->\n <div *ngIf=\"wfcSetting.ShowGrid\" class=\"grid-layer\"></div>\n\n <!-- <div class=\"zoom-toolbar\">\n <button nz-button nzSize=\"small\" (click)=\"zoomOut()\">\u2212</button>\n <span>{{ zoom * 100 | number: \"1.0-0\" }}%</span>\n <button nz-button nzSize=\"small\" (click)=\"zoomIn()\">+</button>\n </div> -->\n\n <!-- SVG EDGES -->\n <svg #svg class=\"edges-layer\" width=\"100%\" height=\"100%\" preserveAspectRatio=\"none\">\n <g [attr.transform]=\"svgTransform\">\n <!-- DEFS -->\n <defs>\n <!-- glow effect -->\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 <!-- arrow markers -->\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\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\n <marker\n id=\"arrow-blue-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"blue\" d=\"M10,0 L0,5 L10,10\"></path>\n </marker>\n\n <marker\n id=\"arrow-red-start\"\n markerWidth=\"10\"\n markerHeight=\"10\"\n viewBox=\"0 0 10 10\"\n refX=\"0\"\n refY=\"5\"\n orient=\"auto\"\n markerUnits=\"strokeWidth\"\n >\n <path class=\"red\" d=\"M10,0 L0,5 L10,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\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 <path\n class=\"edge\"\n [attr.id]=\"'edge-path-' + i\"\n [attr.d]=\"buildPath(e)\"\n marker-end=\"url(#arrow-blue)\"\n [attr.marker-start]=\"e.allowBack ? 'url(#arrow-blue-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- text b\u00E1m theo line -->\n <!-- \n <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text> \n \n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text>\n -->\n\n <!-- text th\u1EB3ng n\u1EB1m ngang -->\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- EDGE \u0110ANG HOVER (LU\u00D4N TR\u00CAN C\u00D9NG) -->\n <ng-container *ngFor=\"let e of hoverEdges; let i = index\">\n <path\n class=\"edge-hit\"\n [attr.d]=\"buildPath(e)\"\n (mouseleave)=\"onMouseLeaveEdge(e)\"\n (click)=\"onClickEdge(e, $event)\"\n ></path>\n\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 [attr.marker-start]=\"e.allowBack ? 'url(#arrow-red-start)' : ''\"\n ></path>\n\n <!-- LABEL -->\n <!-- <text *ngIf=\"e.ActionText\" class=\"edge-label\" dy=\"-6\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.ActionText }}\n </textPath>\n </text>\n\n <text *ngIf=\"e.allowBack && e.labelBack\" class=\"edge-label\" dy=\"14\">\n <textPath [attr.href]=\"'#edge-path-hover-' + i\" startOffset=\"50%\" text-anchor=\"middle\">\n {{ e.labelBack }}\n </textPath>\n </text> -->\n\n <text\n *ngIf=\"e.ActionText\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y - 8\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.ActionText }}\n </text>\n\n <text\n *ngIf=\"e.allowBack && e.labelBack\"\n class=\"edge-label\"\n [attr.x]=\"getEdgeLabelPosition(e).x\"\n [attr.y]=\"getEdgeLabelPosition(e).y + 14\"\n [attr.text-anchor]=\"'middle'\"\n >\n {{ e.labelBack }}\n </text>\n </ng-container>\n\n <!-- preview -->\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 <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 <!-- lstStage -->\n @for (n of lstStage; track $index) {\n @if (n.StageType == \"NODE\") {\n <nz-card\n #nodeEl\n class=\"workflow-node\"\n [attr.data-id]=\"n.Code\"\n [class.selected]=\"n == selectedStage || n == hoverStage || lstSelectedStageId.has(n.WF_TemplateStage_Id)\"\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(); onClickStage(n)\"\n >\n <div class=\"title\">{{ n.Code }}</div>\n\n <div>{{ n.Name }}</div>\n\n @if (!n.editorOption.isReverse) {\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-left\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n } @else {\n <div class=\"connector connector-right reverse\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n <div class=\"connector connector-left reverse\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n }\n </nz-card>\n }\n <!-- START NODE -->\n @else if (n.StageType === \"START\") {\n <nz-card\n class=\"workflow-node workflow-node-start\"\n style=\"border: unset\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\"> </div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageId.has(n.WF_TemplateStage_Id)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.editorOption.isReverseLabel ? -83 : 1\"\n [nzColor]=\"'green'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector RIGHT: output -->\n <div class=\"connector connector-right connector-start\" (click)=\"onClickConnector($event, n, 'right')\"></div>\n </nz-card>\n }\n\n <!-- END NODE -->\n @else if (n.StageType === \"END\") {\n <nz-card\n class=\"workflow-node workflow-node-end\"\n style=\"border: unset\"\n [style.left.px]=\"n.editorOption.x\"\n [style.top.px]=\"n.editorOption.y\"\n [class.connecting-source]=\"isConnectingFrom(n)\"\n nzSize=\"small\"\n (mousedown)=\"onMouseDownNode($event, n)\"\n (click)=\"$event.stopPropagation(); onClickStage(n)\"\n >\n <div class=\"title\"> </div>\n\n <nz-tag\n [class.selected]=\"n == selectedStage || lstSelectedStageId.has(n.WF_TemplateStage_Id)\"\n style=\"position: relative; top: -13px\"\n [style.right.px]=\"n.editorOption.isReverseLabel ? 65 : -5\"\n [nzColor]=\"'red'\"\n >\n {{ n.StageType }}\n </nz-tag>\n\n <!-- connector LEFT: input -->\n <div class=\"connector connector-end\" (click)=\"onClickConnector($event, n, 'left')\"></div>\n </nz-card>\n }\n }\n\n <!-- POINTS -->\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, hoverAction!, $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<!-- drawer TEMPLATE -->\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=\"setting\"></nz-icon> Template </ng-template>\n <ng-container *nzDrawerContent>\n <extend-input [label]=\"'Code'\" [(_ngModel)]=\"template.Code\"></extend-input>\n <extend-input [label]=\"'Name'\" [(_ngModel)]=\"template.Name\"></extend-input>\n <extend-select\n [label]=\"'Type'\"\n [lstItem]=\"template.lstTemplateType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.DocType\"\n ></extend-select>\n <extend-textarea [label]=\"'Desscription'\" [(_ngModel)]=\"template.Description\"></extend-textarea>\n <extend-select\n [label]=\"'Print template'\"\n [lstItem]=\"template.lstTemplatePrint\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"template.TemplatePrint\"\n ></extend-select>\n <extend-checkbox [label]=\"'Active'\" [(_ngModel)]=\"template.IsActive\"></extend-checkbox>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> Stage</h3>\n\n @for (tag of lstStage; track tag) {\n <nz-tag (click)=\"hoverStage = tag\">\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> Stage status</h3>\n\n @for (tag of template.lstStageStatus; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableStageStatus(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseStageStatus(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstStageStatus && template.lstStageStatus.length\" />\n\n @if (!inputStageStatusVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputStageStatus()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputStageStatusElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputStageStatusCode\"\n (keydown.enter)=\"inputStageStatusNameElement.select()\"\n />\n <input\n #inputStageStatusNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputStageStatusName\"\n (blur)=\"handleInputStageStatusConfirm()\"\n (keydown.enter)=\"handleInputStageStatusConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> Action type</h3>\n\n @for (tag of template.lstActionType; track tag) {\n <nz-tag\n [nzMode]=\"checkRemoveableActionType(tag) ? 'closeable' : 'default'\"\n (nzOnClose)=\"handleCloseActionType(tag)\"\n >\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionType && template.lstActionType.length\" />\n\n @if (!inputActionTypeVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInputActionType()\">\n <nz-icon nzType=\"plus\" />\n New Action type\n </nz-tag>\n } @else {\n <input\n #inputActionTypeElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Code\"\n [(ngModel)]=\"inputActionTypeCode\"\n (keydown.enter)=\"inputActionTypeNameElement.select()\"\n />\n <input\n #inputActionTypeNameElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"Name\"\n [(ngModel)]=\"inputActionTypeName\"\n (blur)=\"handleInputActionTypeConfirm()\"\n (keydown.enter)=\"handleInputActionTypeConfirm()\"\n />\n }\n\n <box [height]=\"16\"></box>\n\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> Action status</h3>\n\n @for (tag of template.lstActionStatus; track tag) {\n <nz-tag [nzMode]=\"checkRemoveableActionStatus(tag) ? 'closeable' : 'default'\" (nzOnClose)=\"handleClose(tag)\">\n {{ sliceTagName(tag.Code + (tag.Name ? \" - \" + tag.Name : \"\")) }}\n </nz-tag>\n }\n\n <br *ngIf=\"template.lstActionStatus && template.lstActionStatus.length\" />\n\n @if (!inputVisible) {\n <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInput()\">\n <nz-icon nzType=\"plus\" />\n New Action status\n </nz-tag>\n } @else {\n <input\n #inputElement\n nz-input\n nzSize=\"small\"\n type=\"text\"\n style=\"width: 150px\"\n placeholder=\"+ New Action status\"\n [(ngModel)]=\"inputValue\"\n (blur)=\"handleInputConfirm()\"\n (keydown.enter)=\"handleInputConfirm()\"\n />\n }\n </ng-container>\n\n <ng-template #footerTplTemplate>\n <div nz-flex [nzGap]=\"6\">\n <button nz-button (click)=\"drawTemplateVisibel = false\">Close</button>\n <button nz-button nzDanger (click)=\"save()\">Save</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- drawer STAGE -->\n<nz-drawer\n [nzTitle]=\"drawerTitleStage\"\n [nzPlacement]=\"selectedStage?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzVisible]=\"!!selectedStage\"\n [nzWidth]=\"750\"\n [nzClosable]=\"false\"\n [nzFooter]=\"footerTplNode\"\n (nzOnClose)=\"selectedStage = undefined\"\n>\n <ng-template #drawerTitleStage>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedStage && selectedStage.editorOption) {\n @if (selectedStage.editorOption.drawerPosition == \"left\") {\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the right\"\n (click)=\"selectedStage.editorOption.drawerPosition = 'right'\"\n >\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n STAGE\n } @else {\n STAGE\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the left\"\n (click)=\"selectedStage.editorOption.drawerPosition = 'left'\"\n >\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedStage\">\n <nz-radio-group [(ngModel)]=\"selectedStage.StageType\">\n <label nz-radio nzValue=\"START\" [nzDisabled]=\"selectedStage.StageType != 'START'\">START</label>\n <label nz-radio nzValue=\"NODE\" [nzDisabled]=\"selectedStage.StageType != 'NODE'\">NODE</label>\n <label nz-radio nzValue=\"END\" [nzDisabled]=\"selectedStage.StageType != 'END'\">END</label>\n </nz-radio-group>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"32\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Code'\"\n [layOutType]=\"'vertical'\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Code\"\n ></extend-input>\n\n <extend-textarea\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Name'\"\n [layOutType]=\"'vertical'\"\n [autoSize]=\"true\"\n [disabled]=\"['START', 'END'].indexOf(selectedStage!.StageType) >= 0\"\n [required]=\"true\"\n [(_ngModel)]=\"selectedStage.Name\"\n ></extend-textarea>\n </div>\n\n <div nz-row [nzGutter]=\"32\" class=\"form-item-no-bottom\">\n <extend-input-number\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Sequence'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedStage.SeqValue\"\n ></extend-input-number>\n\n <extend-select\n nz-col\n [nzSpan]=\"16\"\n [label]=\"'Org implement'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstOrg\"\n [valueField]=\"'App_Org_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedStage.App_Org_Id\"\n ></extend-select>\n </div>\n\n <div nz-row [nzGutter]=\"32\" class=\"form-item-no-bottom\">\n <extend-input-number\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Number Day'\"\n [layOutType]=\"'vertical'\"\n [precision]=\"1\"\n [(_ngModel)]=\"selectedStage.NumberDay\"\n ></extend-input-number>\n </div>\n\n @if (selectedStage.editorOption) {\n @if ([\"START\", \"END\"].indexOf(selectedStage.StageType) < 0) {\n <extend-checkbox\n [label]=\"'Reverse'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.editorOption.isReverse\"\n ></extend-checkbox>\n\n <extend-checkbox\n [label]=\"'Require user action'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.IsRequireUser\"\n ></extend-checkbox>\n } @else {\n <extend-checkbox\n [label]=\"'Reverse'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedStage.editorOption.isReverseLabel\"\n ></extend-checkbox>\n }\n }\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\">\n <h3 nz-col><nz-icon nzType=\"send\" nzTheme=\"outline\" /> List Action</h3>\n <div nz-col>\n <button nz-button nzType=\"primary\" nzSize=\"small\" (click)=\"addAction()\">\n <nz-icon nzType=\"plus\"></nz-icon>\n </button>\n </div>\n </div>\n\n <nz-table\n nzSize=\"small\"\n [nzData]=\"selectedStage.lstAction || []\"\n [nzShowPagination]=\"false\"\n [nzNoResult]=\"' '\"\n >\n <thead>\n <tr [hidden]=\"true\">\n <th nzWidth=\"50px\"></th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n @for (action of selectedStage.lstAction; track $index) {\n <tr>\n <td>\n <nz-icon\n nzType=\"delete\"\n nzTheme=\"outline\"\n class=\"color-warn cursor-pointer icon-size-16\"\n (click)=\"$event.stopPropagation(); deleteAction(action)\"\n ></nz-icon>\n </td>\n <td (click)=\"hoverAction = action\">\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"action.ActionText\"\n (_ngModelChange)=\"onchangeActionText(action)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'WF_TemplateStage_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.To_WF_TemplateStage_Id\"\n (_ngModelChange)=\"onchangeNextStage(action)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"action.NextStageStatus\"\n ></extend-select>\n </div>\n <box [height]=\"8\"></box>\n <div nz-row><strong>Role</strong></div>\n <div nz-row>\n <extend-select\n nz-col\n nzSpan=\"24\"\n [size]=\"'small'\"\n [lstItem]=\"lstRole\"\n [valueField]=\"'App_Role_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [multiple]=\"true\"\n [(_ngModel)]=\"action._lstRoleId\"\n (_ngModelChange)=\"onselectedRoleEmail(action)\"\n ></extend-select>\n </div>\n <box [height]=\"8\"></box>\n <div nz-row>\n <strong>Email action</strong>\n </div>\n <div nz-row>\n <extend-select\n nz-col\n nzSpan=\"24\"\n [size]=\"'small'\"\n [lstItem]=\"lstEmailAction\"\n [valueField]=\"'ID'\"\n [displayField]=\"'Name'\"\n [multiple]=\"true\"\n [(_ngModel)]=\"action._lstEmailActionId\"\n (_ngModelChange)=\"onselectedRoleEmail(action)\"\n ></extend-select>\n </div>\n </td>\n </tr>\n }\n </tbody>\n </nz-table>\n\n <box [height]=\"16\"></box>\n </ng-container>\n </ng-container>\n\n <ng-template #footerTplNode>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"\n selectedStage && selectedStage.editorOption && selectedStage.editorOption.drawerPosition == 'left'\n ? 'start'\n : 'end'\n \"\n >\n <button nz-button nzDanger nzDanger (click)=\"save()\">Save</button>\n <button nz-button (click)=\"selectedStage = undefined\">Close</button>\n <button\n *ngIf=\"selectedStage && ['START', 'END'].indexOf(selectedStage.StageType) < 0\"\n nz-button\n nzDanger\n (click)=\"deleteStage()\"\n >\n Delete\n </button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- drawer ACTION -->\n<nz-drawer\n [nzTitle]=\"drawerTitleAction\"\n nzTitle=\"ACTION\"\n [nzPlacement]=\"selectedAction?.editorOption?.drawerPosition == 'left' ? 'left' : 'right'\"\n [nzClosable]=\"false\"\n [nzWidth]=\"750\"\n [nzVisible]=\"!!selectedAction\"\n [nzFooter]=\"footerTplAction\"\n (nzOnClose)=\"selectedAction = undefined\"\n>\n <ng-template #drawerTitleAction>\n <div nz-row nzJustify=\"space-between\">\n @if (selectedAction && selectedAction.editorOption) {\n @if (selectedAction.editorOption.drawerPosition == \"left\") {\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the right\"\n (click)=\"selectedAction.editorOption.drawerPosition = 'right'\"\n >\n <nz-icon nzType=\"double-right\"></nz-icon>\n </button>\n ACTION\n } @else {\n ACTION\n <button\n nz-button\n nzSize=\"small\"\n nz-tooltip=\"To the left\"\n (click)=\"selectedAction.editorOption.drawerPosition = 'left'\"\n >\n <nz-icon nzType=\"double-left\"></nz-icon>\n </button>\n }\n }\n </div>\n </ng-template>\n <ng-container *nzDrawerContent>\n <ng-container *ngIf=\"selectedAction\">\n <strong>{{ selectedAction.FromStageCode }} -> {{ selectedAction.ToStageCode }}</strong>\n\n <box [height]=\"16\"></box>\n\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'WF_TemplateStage_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.To_WF_TemplateStage_Id\"\n (_ngModelChange)=\"onchangeNextStage(selectedAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedAction.NextStageStatus\"\n ></extend-select>\n </div>\n\n <!-- <box [height]=\"16\"></box> -->\n <nz-divider></nz-divider>\n\n <extend-checkbox\n [label]=\"'Allow back'\"\n [labelSpan]=\"0\"\n [(_ngModel)]=\"selectedAction.allowBack\"\n (_ngModelChange)=\"onchangeAllowBack(selectedAction)\"\n ></extend-checkbox>\n\n <box [height]=\"16\"></box>\n\n @if (selectedAction.allowBack) {\n <strong>{{ selectedAction.ToStageCode }} -> {{ selectedAction.FromStageCode }}</strong>\n\n @if (selectedBackAction) {\n <div nz-row [nzGutter]=\"16\" class=\"form-item-no-bottom\">\n <extend-input\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action text'\"\n [layOutType]=\"'vertical'\"\n [(_ngModel)]=\"selectedBackAction.ActionText\"\n (_ngModelChange)=\"onchangeActionText(selectedBackAction)\"\n ></extend-input>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action type'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionType\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionType\"\n ></extend-select>\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Action status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstActionStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.ActionStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.StageStatus\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"lstStage\"\n [valueField]=\"'WF_TemplateStage_Id'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.To_WF_TemplateStage_Id\"\n (_ngModelChange)=\"onchangeNextStage(selectedBackAction)\"\n ></extend-select>\n\n <extend-select\n nz-col\n [nzSpan]=\"8\"\n [label]=\"'Next stage status'\"\n [layOutType]=\"'vertical'\"\n [lstItem]=\"template.lstStageStatus\"\n [valueField]=\"'Code'\"\n [displayFields]=\"['Code', 'Name']\"\n [(_ngModel)]=\"selectedBackAction.NextStageStatus\"\n ></extend-select>\n </div>\n }\n }\n </ng-container>\n </ng-container>\n <ng-template #footerTplAction>\n <div\n nz-flex\n [nzGap]=\"6\"\n [nzJustify]=\"selectedAction && selectedAction.editorOption.drawerPosition == 'left' ? 'start' : 'end'\"\n >\n <button nz-button nzDanger nzDanger (click)=\"save()\">Save</button>\n <button nz-button (click)=\"selectedAction = undefined\">Close</button>\n <button nz-button nzDanger (click)=\"deleteAction(selectedAction!)\">Delete</button>\n </div>\n </ng-template>\n</nz-drawer>\n\n<!-- setting editor -->\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> Editor </ng-template>\n <ng-container *nzDrawerContent>\n <div class=\"form-item-no-bottom\">\n <extend-checkbox [label]=\"'Show grid'\" [labelSpan]=\"0\" [(_ngModel)]=\"wfcSetting.ShowGrid\"></extend-checkbox>\n\n <box [height]=\"16\"></box>\n </div>\n </ng-container>\n</nz-drawer>\n", styles: ["@charset \"UTF-8\";.workflow-canvas{position:relative;width:100%;height:600px;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:10000px;height:10000px}.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 .title{font-weight:600;margin-bottom:6px}.workflow-node.connecting-source,.workflow-node.selected,.workflow-node:hover:not(.workflow-node-start,.workflow-node-end){outline:2px dashed #1890ff}.workflow-node-start{background-color:unset;display:flex;justify-content:right}.workflow-node-end{background-color:unset;display:flex}.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:-3px;background:green;box-shadow:0 0 0 3px #1890ff4d}.connector-end{width:16px;height:16px;left:-6px;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}.zoom-toolbar{position:absolute;top:8px;left:8px;z-index:10;display:flex;align-items:center;gap:6px;background:#fff;padding:4px 6px;border-radius:6px;box-shadow:0 2px 6px #00000026}.zoom-toolbar span{min-width:40px;text-align:center;font-size:12px}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}\n"] }]
|
|
4288
4445
|
}], propDecorators: { lstOrg: [{
|
|
4289
4446
|
type: Input
|
|
4290
|
-
}],
|
|
4291
|
-
type: Input
|
|
4292
|
-
}], lstTemplatePrint: [{
|
|
4293
|
-
type: Input
|
|
4294
|
-
}], template: [{
|
|
4295
|
-
type: Input
|
|
4296
|
-
}], lstStage: [{
|
|
4297
|
-
type: Input
|
|
4298
|
-
}], lstAction: [{
|
|
4447
|
+
}], lstRole: [{
|
|
4299
4448
|
type: Input
|
|
4300
4449
|
}], onSave: [{
|
|
4301
4450
|
type: Output,
|
|
4302
4451
|
args: ['onSave']
|
|
4452
|
+
}], onDeleteStage: [{
|
|
4453
|
+
type: Output,
|
|
4454
|
+
args: ['onDeleteStage']
|
|
4455
|
+
}], onDeleteAction: [{
|
|
4456
|
+
type: Output,
|
|
4457
|
+
args: ['onDeleteAction']
|
|
4303
4458
|
}], canvasRef: [{
|
|
4304
4459
|
type: ViewChild,
|
|
4305
4460
|
args: ['canvas', { static: true }]
|
|
@@ -4967,5 +5122,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImpor
|
|
|
4967
5122
|
* Generated bundle index. Do not edit.
|
|
4968
5123
|
*/
|
|
4969
5124
|
|
|
4970
|
-
export { AnimatedDigitComponent, AppGlobals, AppStorage, AuthGuard, AutoFocusDirective, BarGraphComponent, BaseComponent, BaseGuardChangeComponent, BaseOverlayComponent, Box, Breadcrumb, CheckModel, CommonService, DashcardComponent, DateInputParserDirective, DateTimeHelper, DoughnutGraphComponent, DownloadHelper, ENUM_ResponseType, ExtendCheckbox, ExtendDatePicker, ExtendDateRangePicker, ExtendInput, ExtendInputNumber, ExtendSelectComponent, ExtendTextArea, GlobalSpinnerComponent, GridFilter, HTTPService, Height, LimitWordsPipe, LineGraphComponent, LoadingService, NoPermission, NotiService, NullIfEmptyDirective, NumberOnlyDirective, OrderOption, PagingData, PagingModel, PdfViewerComponent, RouteMonitorService, TableHeader, ThemeService, TokenStorage, TranslateKey, UnsavedChangesGuard, UpperCaseFirsLetterEachWordDirective, UppercaseDirective, UppercaseFirstLetterDirective, VscService, Width, WorkflowEditorComponent, XLSXHelper, authInterceptor };
|
|
5125
|
+
export { AnimatedDigitComponent, AppGlobals, AppStorage, AuthGuard, AutoFocusDirective, BarGraphComponent, BaseComponent, BaseGuardChangeComponent, BaseOverlayComponent, Box, Breadcrumb, CheckModel, CommonService, DashcardComponent, DateInputParserDirective, DateTimeHelper, DoughnutGraphComponent, DownloadHelper, ENUM_ResponseType, ExtendCheckbox, ExtendDatePicker, ExtendDateRangePicker, ExtendInput, ExtendInputNumber, ExtendSelectComponent, ExtendTextArea, GlobalSpinnerComponent, GridFilter, HTTPService, Height, LimitWordsPipe, LineGraphComponent, LoadingService, NoPermission, NotiService, NullIfEmptyDirective, NumberOnlyDirective, OrderOption, PagingData, PagingModel, PdfViewerComponent, RouteMonitorService, TableHeader, ThemeService, TokenStorage, TranslateKey, UnsavedChangesGuard, UpperCaseFirsLetterEachWordDirective, UppercaseDirective, UppercaseFirstLetterDirective, VscService, Width, Workflow, WorkflowAction, WorkflowActionEditorOption, WorkflowEditorComponent, WorkflowStage, WorkflowStageEditorOption, XLSXHelper, authInterceptor };
|
|
4971
5126
|
//# sourceMappingURL=brggroup-share-lib.mjs.map
|