@xw-components/formula-editor 18.1.0

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.
@@ -0,0 +1,699 @@
1
+ import * as i5 from '@angular/common';
2
+ import { CommonModule } from '@angular/common';
3
+ import * as i0 from '@angular/core';
4
+ import { InjectionToken, inject, Injectable, input, signal, effect, ViewChild, Component } from '@angular/core';
5
+ import * as i3 from '@angular/forms';
6
+ import { FormsModule } from '@angular/forms';
7
+ import { Node, mergeAttributes, Editor } from '@tiptap/core';
8
+ import StarterKit from '@tiptap/starter-kit';
9
+ import * as i7 from 'ng-zorro-antd/button';
10
+ import { NzButtonModule } from 'ng-zorro-antd/button';
11
+ import { NzHighlightPipe } from 'ng-zorro-antd/core/highlight';
12
+ import * as i1 from 'ng-zorro-antd/grid';
13
+ import { NzColDirective, NzGridModule } from 'ng-zorro-antd/grid';
14
+ import * as i4 from 'ng-zorro-antd/icon';
15
+ import { NzIconModule } from 'ng-zorro-antd/icon';
16
+ import * as i2 from 'ng-zorro-antd/input';
17
+ import { NzInputModule } from 'ng-zorro-antd/input';
18
+ import { NzMessageService } from 'ng-zorro-antd/message';
19
+ import * as i9 from 'ng-zorro-antd/tooltip';
20
+ import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
21
+ import * as i6 from 'ng-zorro-antd/tree';
22
+ import { NzTreeModule } from 'ng-zorro-antd/tree';
23
+ import { DomSanitizer } from '@angular/platform-browser';
24
+ import * as i8 from 'ng-zorro-antd/core/transition-patch';
25
+
26
+ const FormulaEditorRequestServiceToken = new InjectionToken('FormulaEditorRequestServiceToken');
27
+ /**
28
+ * 公式编辑器请求服务,用于获取函数列表、字段列表、指标列表和校验公式格式
29
+ * 实现类需要实现四个方法。如果有部分方法不需要,可以实现空方法。
30
+ */
31
+ class FormulaEditorRequestService {
32
+ constructor() { }
33
+ /**
34
+ * 获取字段的描述
35
+ * @param item 字段对象
36
+ * @returns 描述字符串
37
+ */
38
+ getFieldDescription() {
39
+ return Promise.resolve('');
40
+ }
41
+ }
42
+
43
+ /**
44
+ * 输入项类型,可选择指标模式或字段模式
45
+ */
46
+ var ItemType;
47
+ (function (ItemType) {
48
+ ItemType["Field"] = "field";
49
+ ItemType["Template"] = "template"; // 模板模式
50
+ })(ItemType || (ItemType = {}));
51
+ /**
52
+ * 输入校验格式方法
53
+ */
54
+ var CheckFormatMethod;
55
+ (function (CheckFormatMethod) {
56
+ CheckFormatMethod["self"] = "self";
57
+ CheckFormatMethod["server"] = "server"; // 自定义异步校验
58
+ })(CheckFormatMethod || (CheckFormatMethod = {}));
59
+ /**
60
+ * 函数列表模式,可选择列表或树模式
61
+ */
62
+ var FuncListType;
63
+ (function (FuncListType) {
64
+ FuncListType["List"] = "list";
65
+ FuncListType["Tree"] = "tree"; // 树模式
66
+ })(FuncListType || (FuncListType = {}));
67
+ const OPERATOR_LIST = [
68
+ {
69
+ type: 'add',
70
+ name: '+',
71
+ description: '加法'
72
+ },
73
+ {
74
+ type: 'minus',
75
+ name: '-',
76
+ description: '减法'
77
+ },
78
+ {
79
+ type: 'multiply',
80
+ name: '*',
81
+ description: '乘法'
82
+ },
83
+ {
84
+ type: 'divide',
85
+ name: '/',
86
+ description: '除法'
87
+ },
88
+ {
89
+ type: 'left-parenthesis',
90
+ name: '(',
91
+ description: '左括号'
92
+ },
93
+ {
94
+ type: 'right-parenthesis',
95
+ name: ')',
96
+ description: '右括号'
97
+ }
98
+ ];
99
+
100
+ class FormulaEditorService {
101
+ constructor() {
102
+ this.sanitizer = inject(DomSanitizer);
103
+ }
104
+ initNodes() {
105
+ this.createFuncNode();
106
+ this.createFieldNode();
107
+ }
108
+ createFieldNode() {
109
+ this.fieldNode = Node.create({
110
+ name: 'field',
111
+ inline: true,
112
+ group: 'inline',
113
+ selectable: false,
114
+ draggable: true,
115
+ atom: true,
116
+ addAttributes() {
117
+ return {
118
+ id: {
119
+ default: null
120
+ },
121
+ name: {
122
+ default: ''
123
+ },
124
+ className: {
125
+ default: ''
126
+ },
127
+ dataType: {
128
+ default: 'field'
129
+ }
130
+ };
131
+ },
132
+ renderText({ node }) {
133
+ return `${node.attrs['name']}`;
134
+ },
135
+ parseHTML() {
136
+ return [{ tag: 'div[data-type="field"]' }];
137
+ },
138
+ renderHTML({ HTMLAttributes, node }) {
139
+ return [
140
+ 'div',
141
+ mergeAttributes({
142
+ 'data-type': 'field',
143
+ class: `field-node ${node.attrs['className']}` || '',
144
+ contenteditable: 'false',
145
+ style: `display: inline-block;margin: 0 4px;font-size: 13px;height: 18px;line-height: 18px;`
146
+ }, HTMLAttributes),
147
+ node.attrs['name']
148
+ ];
149
+ }
150
+ });
151
+ }
152
+ createFuncNode() {
153
+ this.funcNode = Node.create({
154
+ name: 'func',
155
+ inline: true,
156
+ group: 'inline',
157
+ selectable: false,
158
+ draggable: false,
159
+ content: 'inline*',
160
+ atom: true,
161
+ addAttributes() {
162
+ return {
163
+ id: {
164
+ default: null
165
+ },
166
+ name: {
167
+ default: ''
168
+ },
169
+ className: {
170
+ default: ''
171
+ },
172
+ dataType: {
173
+ default: 'func'
174
+ }
175
+ };
176
+ },
177
+ renderText({ node }) {
178
+ const funcName = node.attrs['name'] || '';
179
+ const childrenText = node.content.content
180
+ .map(child => {
181
+ if (child.text) {
182
+ return child.text;
183
+ }
184
+ if (child.type && child.type.spec && child.type.spec['toText']) {
185
+ return child.type.spec['toText']({ node: child });
186
+ }
187
+ return '';
188
+ })
189
+ .join('');
190
+ return `${funcName}(${childrenText})`;
191
+ },
192
+ parseHTML() {
193
+ return [{ tag: 'div[data-type="func"]' }];
194
+ },
195
+ addNodeView() {
196
+ return ({ node }) => {
197
+ const createElement = (tag, props = {}) => {
198
+ const element = document.createElement(tag);
199
+ Object.entries(props).forEach(([key, value]) => {
200
+ if (key === 'style') {
201
+ Object.entries(value).forEach(([styleKey, styleValue]) => {
202
+ element.style[styleKey] = styleValue;
203
+ });
204
+ }
205
+ else if (key === 'innerText') {
206
+ element.innerText = value;
207
+ }
208
+ else if (key === 'className') {
209
+ element.className = value;
210
+ }
211
+ else {
212
+ element.setAttribute(key, value);
213
+ }
214
+ });
215
+ return element;
216
+ };
217
+ const className = node.attrs['className'] || '';
218
+ const funcName = node.attrs['name'];
219
+ const container = createElement('span', {
220
+ style: {
221
+ display: 'inline-block',
222
+ margin: '0 4px',
223
+ fontSize: '13px'
224
+ }
225
+ });
226
+ const content = createElement('span', {
227
+ style: {
228
+ whiteSpace: 'pre-wrap',
229
+ display: 'inline-block'
230
+ },
231
+ contenteditable: 'true'
232
+ });
233
+ const before = createElement('span', {
234
+ innerText: `${funcName} `,
235
+ contenteditable: 'false',
236
+ className
237
+ });
238
+ const bracket = (value, style = {}) => {
239
+ return createElement('span', {
240
+ innerText: value,
241
+ contenteditable: 'false',
242
+ style: {
243
+ ...style
244
+ }
245
+ });
246
+ };
247
+ container.append(before, bracket('(', { marginRight: '2px' }), content, bracket(')', { marginLeft: '2px' }));
248
+ return {
249
+ dom: container,
250
+ contentDOM: content
251
+ };
252
+ };
253
+ }
254
+ });
255
+ }
256
+ /**
257
+ * 校验公式的JSON表示是否有效
258
+ * @param formula 公式的JSON表示
259
+ * @returns 校验结果,包含是否有效和错误信息数组
260
+ */
261
+ validateFormula(formula) {
262
+ const errors = [];
263
+ if (!formula) {
264
+ errors.push('公式不能为空');
265
+ return { isValid: false, errors };
266
+ }
267
+ if (formula.type !== 'doc') {
268
+ errors.push('公式根节点类型必须是 doc');
269
+ }
270
+ if (!formula.content || !Array.isArray(formula.content)) {
271
+ errors.push('公式必须包含 content 数组');
272
+ return { isValid: false, errors };
273
+ }
274
+ for (const paragraph of formula.content) {
275
+ if (paragraph.type !== 'paragraph') {
276
+ errors.push('段落类型必须是 paragraph');
277
+ continue;
278
+ }
279
+ if (!paragraph.content || !Array.isArray(paragraph.content)) {
280
+ continue;
281
+ }
282
+ for (const node of paragraph.content) {
283
+ this.validateNode(node, errors);
284
+ }
285
+ }
286
+ return {
287
+ isValid: errors.length === 0,
288
+ errors
289
+ };
290
+ }
291
+ /**
292
+ * 从JSON数据中提取内容文本或HTML
293
+ * @param jsonData 公式的JSON表示
294
+ * @param outputFormat 输出格式,'text'或'html',默认'text'
295
+ * @returns 提取的内容文本或HTML字符串
296
+ */
297
+ getContentFromJson(jsonData, outputFormat = 'text') {
298
+ if (!jsonData || !jsonData.content)
299
+ return '';
300
+ return outputFormat === 'html'
301
+ ? this.sanitizer.bypassSecurityTrustHtml(this.processContentToHtml(jsonData.content))
302
+ : this.processContent(jsonData.content);
303
+ }
304
+ processContent(content) {
305
+ if (!content || !Array.isArray(content))
306
+ return '';
307
+ return content.map(item => this.processNode(item)).join('');
308
+ }
309
+ processNode(node) {
310
+ if (!node)
311
+ return '';
312
+ switch (node.type) {
313
+ case 'func':
314
+ return this.processFuncNode(node);
315
+ case 'field':
316
+ return `{${node.attrs?.name || ''}}`;
317
+ case 'metric':
318
+ return `[${node.attrs?.name || ''}]`;
319
+ case 'text':
320
+ return node.text || '';
321
+ case 'paragraph':
322
+ return this.processContent(node.content);
323
+ case 'doc':
324
+ return this.processContent(node.content);
325
+ default:
326
+ return '';
327
+ }
328
+ }
329
+ processFuncNode(node) {
330
+ const funcName = node.attrs?.name || '';
331
+ const content = this.processContent(node.content);
332
+ return `${funcName}(${content})`;
333
+ }
334
+ processContentToHtml(content) {
335
+ if (!content || !Array.isArray(content))
336
+ return '';
337
+ return content.map(item => this.processNodeToHtml(item)).join('');
338
+ }
339
+ processNodeToHtml(node) {
340
+ if (!node)
341
+ return '';
342
+ switch (node.type) {
343
+ case 'func':
344
+ return this.processFuncNodeToHtml(node);
345
+ case 'field':
346
+ return `<span class="${node.attrs?.className || ''}" style="display: inline-block; margin: 0 4px;height: 18px;line-height: 18px;">${node.attrs?.name || ''}</span>`;
347
+ case 'text':
348
+ return this.escapeHtml(node.text || '');
349
+ case 'paragraph':
350
+ return this.processContentToHtml(node.content);
351
+ case 'doc':
352
+ return this.processContentToHtml(node.content);
353
+ default:
354
+ return '';
355
+ }
356
+ }
357
+ processFuncNodeToHtml(node) {
358
+ const funcName = node.attrs?.name || '';
359
+ const className = node.attrs?.className || '';
360
+ const content = this.processContentToHtml(node.content);
361
+ return `<span style="display: inline-block; margin: 0 4px;"><span contenteditable="false" class="${className}">${funcName}(</span><span style="white-space: pre-wrap; display: inline-block; margin: 0 4px;" contenteditable="true">${content}</span><span contenteditable="false" class="${className}">)</span></span>`;
362
+ }
363
+ escapeHtml(text) {
364
+ const div = document.createElement('div');
365
+ div.textContent = text;
366
+ return div.innerHTML;
367
+ }
368
+ validateNode(node, errors, path = '') {
369
+ if (!node || !node.type) {
370
+ return;
371
+ }
372
+ const currentPath = path ? `${path} > ${node.type}` : node.type;
373
+ if (node.type === 'func') {
374
+ this.validateFuncNode(node, errors, currentPath);
375
+ }
376
+ }
377
+ validateFuncNode(node, errors, path) {
378
+ if (!node.content || !Array.isArray(node.content)) {
379
+ return;
380
+ }
381
+ const content = node.content;
382
+ const length = content.length;
383
+ for (let i = 0; i < length; i++) {
384
+ const currentItem = content[i];
385
+ const nextItem = content[i + 1];
386
+ if (currentItem.type === 'field' || currentItem.type === 'func') {
387
+ if (i < length - 1) {
388
+ if (nextItem && nextItem.type === 'text') {
389
+ const text = nextItem.text || '';
390
+ if (!text.startsWith(',')) {
391
+ errors.push(`${path}: 参数之间必须用逗号分隔,位置 ${i + 1}`);
392
+ }
393
+ }
394
+ else {
395
+ errors.push(`${path}: 参数之间必须用逗号分隔,位置 ${i + 1}`);
396
+ }
397
+ }
398
+ }
399
+ if (currentItem.type === 'func') {
400
+ this.validateFuncNode(currentItem, errors, `${path} > ${currentItem.attrs?.name || 'func'}`);
401
+ }
402
+ }
403
+ }
404
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormulaEditorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
405
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormulaEditorService, providedIn: 'root' }); }
406
+ }
407
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormulaEditorService, decorators: [{
408
+ type: Injectable,
409
+ args: [{
410
+ providedIn: 'root'
411
+ }]
412
+ }] });
413
+
414
+ const ICONS = {
415
+ cheng: `<svg class="icon" width="16px" height="16px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M460.8 896c-7.1 0-12.8-5.7-12.8-12.8V614.8L268.8 794c-5 5-13.1 5.1-18.1 0.1l-0.1-0.1-49.5-49.8c-5-5-5.1-13.1-0.1-18.1l0.1-0.1L383 544.1H140.8c-7.1 0-12.8-5.7-12.8-12.8v-70.4c0-7.1 5.7-12.8 12.8-12.8h239.4L200.9 268.9c-5-5-5.1-13.1-0.1-18.1l0.1-0.1 49.5-49.8c5-5 13.1-5.1 18.1-0.1l0.1 0.1 179.2 179.2V140.8c0-7.1 5.7-12.8 12.8-12.8H531c7.1 0 12.8 5.7 12.8 12.8v242.3L725.9 201c5-4.9 12.9-4.9 17.9 0l49.8 49.8c5 5 5.1 13.1 0.1 18.1l-0.1 0.1-179.2 179.1h268.4c7.1 0 12.8 5.7 12.8 12.8v70.4c0 7.1-5.7 12.8-12.8 12.8H611.6L793.5 726c5 5 5.1 13.1 0.1 18.1l-0.1 0.1-49.8 49.8c-5 4.9-12.9 4.9-17.9 0L543.7 611.8v271.6c0 7.1-5.7 12.8-12.8 12.8l-70.1-0.2z" /></svg>`,
416
+ chu: `<svg class="icon" width="16px" height="16px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M808.3 283.6L283.6 808.3c-5 5-13.1 5-18.1 0l-49.8-49.8c-5-5-5-13.1 0-18.1l524.7-524.7c5-5 13.1-5 18.1 0l49.8 49.8c4.9 5 4.9 13.1 0 18.1z" /></svg>`,
417
+ jia: `<svg class="icon" width="16px" height="16px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M476.8 896c-7.1 0-12.8-5.7-12.8-12.8V560H140.8c-7.1 0-12.8-5.7-12.8-12.8v-70.4c0-7.1 5.7-12.8 12.8-12.8H464V140.8c0-7.1 5.7-12.8 12.8-12.8h70.4c7.1 0 12.8 5.7 12.8 12.8V464h323.2c7.1 0 12.8 5.7 12.8 12.8v70.4c0 7.1-5.7 12.8-12.8 12.8H560v323.2c-0.2 7-5.8 12.7-12.8 12.8h-70.4z" /></svg>`,
418
+ jian: `<svg class="icon" width="16px" height="16px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M140.8 464h742.4c7.1 0 12.8 5.7 12.8 12.8v70.4c0 7.1-5.7 12.8-12.8 12.8H140.8c-7.1 0-12.8-5.7-12.8-12.8v-70.4c0-7.1 5.7-12.8 12.8-12.8z" /></svg>`,
419
+ youkuohao: `<svg class="icon" width="16px" height="16px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M416 163c38.7 49.3 68.8 104.8 88.9 164.1 19.8 59.6 29.7 122.1 29.3 184.9 1.1 62.3-8.5 124.2-28.4 183.2-23.2 59.2-53.3 115.4-89.8 167.4l56.9 33.3c42.9-56 76.8-118.4 100.4-184.9 23.2-64.1 34.9-131.8 34.7-199.9 0.3-69.3-11.4-138-34.7-203.3-23.2-65-57.2-125.8-100.4-179.8L416 163z" /></svg>`,
420
+ zuokuohao: `<svg class="icon" width="16px" height="16px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M608 163c-38.7 49.3-68.8 104.8-88.9 164.1-19.8 59.6-29.7 122.1-29.3 184.9-1.1 62.3 8.5 124.2 28.4 183.2 23.1 59.2 53.2 115.4 89.6 167.4L550.9 896c-42.8-56-76.6-118.4-100.2-184.9-23.2-64.1-34.9-131.8-34.7-199.9-0.3-69.3 11.4-138 34.7-203.3C473.9 242.8 507.9 182 551.1 128l56.9 35z" /></svg>`
421
+ };
422
+
423
+ /**
424
+ * 公式编辑器组件
425
+ * 用于创建和编辑计算公式,支持函数、指标和字段的插入与验证
426
+ * 依赖className与在使用组件处使用穿透样式实现样式
427
+ */
428
+ class FormulaEditorComponent {
429
+ getOperatorIcon(type) {
430
+ const iconMap = {
431
+ add: ICONS.jia,
432
+ minus: ICONS.jian,
433
+ multiply: ICONS.cheng,
434
+ divide: ICONS.chu,
435
+ 'left-parenthesis': ICONS.zuokuohao,
436
+ 'right-parenthesis': ICONS.youkuohao
437
+ };
438
+ return this.sanitizer.bypassSecurityTrustHtml(iconMap[type] || '');
439
+ }
440
+ /**
441
+ * 构造函数
442
+ * 初始化信号监听,处理搜索和项目类型变化
443
+ */
444
+ constructor() {
445
+ this.formulaEditorService = inject(FormulaEditorService);
446
+ this.sanitizer = inject(DomSanitizer);
447
+ this.msg = inject(NzMessageService);
448
+ this.formulaEditorRequestService = inject(FormulaEditorRequestServiceToken);
449
+ /**
450
+ * 项目类型,决定显示字段或自定义
451
+ * 默认值:ItemType.Field
452
+ */
453
+ this.itemType = input(ItemType.Field);
454
+ /**
455
+ * 字段标题,当项目类型为字段时显示
456
+ * 默认值:'字段'
457
+ */
458
+ this.fieldTitle = input('字段');
459
+ /**
460
+ * 格式检查方法
461
+ * 默认值:CheckFormatMethod.self
462
+ */
463
+ this.checkFormatMethod = input(CheckFormatMethod.self);
464
+ /**
465
+ * 函数列表显示类型
466
+ * 默认值:FuncListType.Tree
467
+ */
468
+ this.functionListType = input(FuncListType.Tree);
469
+ this.itemTemplate = input(null);
470
+ this._itemType = ItemType;
471
+ this._funcListType = FuncListType;
472
+ this.searchWord = '';
473
+ this.fieldListOrigin = [];
474
+ this.fieldList = [];
475
+ this.checkLoading = false;
476
+ this.showDescription = true;
477
+ this.funcNode = [];
478
+ this.fieldDescription = '';
479
+ this.editDescription = '请选择函数';
480
+ this.editDescShow = 'none';
481
+ this.searchField = signal('');
482
+ this.searchFunction = signal('');
483
+ this._operatorList = OPERATOR_LIST;
484
+ effect(() => {
485
+ const searchWord = this.searchField();
486
+ this.fieldList = this.fieldListOrigin.filter(item => item.name.includes(searchWord));
487
+ });
488
+ effect(() => {
489
+ const itemType = this.itemType();
490
+ if (itemType === ItemType.Field) {
491
+ this.formulaEditorRequestService.getFields().then(res => {
492
+ this.fieldListOrigin = res;
493
+ this.fieldList = [...this.fieldListOrigin];
494
+ });
495
+ }
496
+ });
497
+ }
498
+ ngOnInit() {
499
+ this.formulaEditorRequestService.getFunctions().then(res => {
500
+ this.funcNode = res;
501
+ });
502
+ this.formulaEditorRequestService.getFieldDescription().then(res => {
503
+ this.fieldDescription = res;
504
+ });
505
+ }
506
+ ngAfterViewInit() {
507
+ this.formulaEditorService.initNodes();
508
+ this.editorObj = new Editor({
509
+ element: this.editor.nativeElement,
510
+ extensions: [
511
+ StarterKit.configure({
512
+ blockquote: false,
513
+ codeBlock: false,
514
+ code: false
515
+ }),
516
+ this.formulaEditorService.funcNode,
517
+ this.formulaEditorService.fieldNode
518
+ ]
519
+ });
520
+ }
521
+ insertFunc(func) {
522
+ this.editorObj
523
+ .chain()
524
+ .insertContent({
525
+ type: 'func',
526
+ attrs: {
527
+ name: func.name,
528
+ id: func.id,
529
+ className: `text-func-${func.className}`
530
+ },
531
+ content: []
532
+ })
533
+ .focus()
534
+ .run();
535
+ }
536
+ insertField(field) {
537
+ this.editorObj
538
+ .chain()
539
+ .insertContent({
540
+ type: 'field',
541
+ attrs: {
542
+ name: field.name,
543
+ id: field.id,
544
+ className: `text-field-${field.className}`
545
+ }
546
+ })
547
+ .focus()
548
+ .run();
549
+ }
550
+ insertOperator(operator) {
551
+ this.editorObj
552
+ .chain()
553
+ .insertContent({
554
+ type: 'text',
555
+ text: operator
556
+ })
557
+ .focus()
558
+ .run();
559
+ }
560
+ functionClick(node) {
561
+ const func = node.node.origin;
562
+ this.editDescription = func.description || '';
563
+ this.editDescShow = 'func';
564
+ this.insertFunc(func);
565
+ }
566
+ /**
567
+ * 获取公式JSON
568
+ * @returns 公式的JSON表示
569
+ * @example
570
+ * // 返回示例
571
+ * {
572
+ * "type": "doc",
573
+ * "content": [
574
+ * {
575
+ * "type": "paragraph",
576
+ * "content": [
577
+ * {
578
+ * "type": "func",
579
+ * "attrs": {
580
+ * "name": "SUM",
581
+ * "id": "sum",
582
+ * "className": "text-func-agg"
583
+ * }
584
+ * }
585
+ * ]
586
+ * }
587
+ * ]
588
+ * }
589
+ */
590
+ getFormula() {
591
+ const formula = this.editorObj.getJSON();
592
+ return formula;
593
+ }
594
+ /**
595
+ * 获取公式文本
596
+ * @returns 公式的纯文本表示
597
+ * @example
598
+ * // 返回示例
599
+ * "SUM(field1, field2)"
600
+ */
601
+ getFormulaText() {
602
+ const formulaText = this.editorObj.getText();
603
+ return formulaText;
604
+ }
605
+ checkFormat() {
606
+ if (this.checkFormatMethod() === CheckFormatMethod.self) {
607
+ const result = this.validateFormula();
608
+ if (result.isValid) {
609
+ this.msg.success('格式校验通过');
610
+ }
611
+ else {
612
+ this.msg.error(`格式校验不通过: ${result.errors.join(', ')}`);
613
+ this.editDescription = result.errors.join(', ');
614
+ this.editDescShow = 'error';
615
+ }
616
+ }
617
+ else {
618
+ this.checkLoading = true;
619
+ this.formulaEditorRequestService.validateFormula(this.getFormula()).then(res => {
620
+ this.checkLoading = false;
621
+ if (res.isValid) {
622
+ this.msg.success('格式校验通过');
623
+ }
624
+ else {
625
+ this.msg.error(`格式校验不通过: ${res.errors.join(', ')}`);
626
+ this.editDescription = res.errors.join(', ');
627
+ this.editDescShow = 'error';
628
+ }
629
+ });
630
+ }
631
+ }
632
+ /**
633
+ * 从JSON加载公式
634
+ * @param formula 公式的JSON表示
635
+ * @example
636
+ * // 使用示例
637
+ * const formula = {
638
+ * "type": "doc",
639
+ * "content": [
640
+ * {
641
+ * "type": "paragraph",
642
+ * "content": [
643
+ * {
644
+ * "type": "func",
645
+ * "attrs": {
646
+ * "name": "SUM",
647
+ * "id": "sum",
648
+ * "className": "text-func-agg"
649
+ * }
650
+ * }
651
+ * ]
652
+ * }
653
+ * ]
654
+ * };
655
+ * formulaEditor.loadFormula(formula);
656
+ */
657
+ loadFormula(formula) {
658
+ if (!formula || !this.editorObj) {
659
+ return;
660
+ }
661
+ this.editorObj.commands.setContent(formula);
662
+ }
663
+ // 校验公式
664
+ validateFormula() {
665
+ const formula = this.editorObj.getJSON();
666
+ const result = this.formulaEditorService.validateFormula(formula);
667
+ return result;
668
+ }
669
+ toggleDescription() {
670
+ this.showDescription = !this.showDescription;
671
+ }
672
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormulaEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
673
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FormulaEditorComponent, isStandalone: true, selector: "app-formula-editor", inputs: { itemType: { classPropertyName: "itemType", publicName: "itemType", isSignal: true, isRequired: false, transformFunction: null }, fieldTitle: { classPropertyName: "fieldTitle", publicName: "fieldTitle", isSignal: true, isRequired: false, transformFunction: null }, checkFormatMethod: { classPropertyName: "checkFormatMethod", publicName: "checkFormatMethod", isSignal: true, isRequired: false, transformFunction: null }, functionListType: { classPropertyName: "functionListType", publicName: "functionListType", isSignal: true, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "editor", first: true, predicate: ["editor"], descendants: true }], ngImport: i0, template: "<div nz-row class=\"formula-editor\">\n <div nz-col nzSpan=\"10\" class=\"editor-box\">\n <div class=\"editor-title\">\n <div class=\"label-title label-require\">\u5B57\u6BB5\u8868\u8FBE\u5F0F</div>\n <button nz-button nzType=\"link\" nzSize=\"small\" [nzLoading]=\"checkLoading\" (click)=\"checkFormat()\">\u683C\u5F0F\u6821\u9A8C</button>\n </div>\n <div class=\"edit-box\">\n <div class=\"edit-operation-box\">\n @for (item of _operatorList; track item) {\n <div class=\"edit-operation-item\" (click)=\"insertOperator(item.name)\">\n <span class=\"operator-icon\" [innerHTML]=\"getOperatorIcon(item.type)\"></span>\n </div>\n }\n </div>\n <div #editor class=\"editor\"></div>\n @if (editDescShow !== 'none') {\n <div class=\"edit-description-box\">\n <div class=\"edit-description-head\" [style]=\"{ marginBottom: !showDescription ? '10px' : '0' }\">\n <span class=\"edit-description-title\">{{ editDescShow === 'func' ? '\u51FD\u6570\u91CA\u4E49' : '\u6821\u9A8C\u9519\u8BEF\u4FE1\u606F' }}</span>\n <span\n class=\"edit-description-icon\"\n nz-icon\n [nzType]=\"showDescription ? 'down' : 'up'\"\n nzTheme=\"outline\"\n (click)=\"toggleDescription()\"\n ></span>\n </div>\n @if (showDescription) {\n <div class=\"edit-description-text\"> {{ editDescription }} </div>\n }\n </div>\n }\n </div>\n </div>\n @switch (itemType()) {\n @case (_itemType.Field) {\n <div nz-col nzSpan=\"7\" class=\"field-box\">\n <div class=\"label-title\"\n >{{ fieldTitle() }}\n @if (fieldDescription) {\n <span nz-icon nzType=\"question-circle\" nzTheme=\"outline\" nz-tooltip [nzTooltipTitle]=\"fieldDescription\"></span>\n }\n </div>\n <nz-input-group [nzSuffix]=\"suffixIconSearch\">\n <input type=\"text\" nz-input placeholder=\"\u641C\u7D22\" [(ngModel)]=\"searchField\" />\n </nz-input-group>\n <ng-template #suffixIconSearch>\n <i nz-icon nzType=\"search\"></i>\n </ng-template>\n <div class=\"field-list\">\n @for (item of fieldList; track item) {\n <div (click)=\"insertField(item)\" [class]=\"item.className ? 'item-field-' + item.className : ''\" class=\"field-list-item\">\n @if (item.image) {\n <img class=\"field-img\" [src]=\"item.image\" />\n }\n @if (item.icon) {\n <span class=\"field-icon\" nz-icon [nzIconfont]=\"item.icon\"></span>\n }\n <span class=\"field-name\" [innerHTML]=\"item.name | nzHighlight: searchField() : 'i' : 'node-highlight'\"></span>\n @if (item.description) {\n <span\n class=\"desc-icon\"\n nz-icon\n nzType=\"question-circle\"\n nzTheme=\"outline\"\n nz-tooltip\n [nzTooltipTitle]=\"item.description\"\n ></span>\n }\n </div>\n }\n </div>\n </div>\n }\n @case (_itemType.Template) {\n <div nz-col nzSpan=\"7\" class=\"field-box\">\n <ng-container *ngTemplateOutlet=\"itemTemplate()\"></ng-container>\n </div>\n }\n }\n <div nz-col nzSpan=\"7\" class=\"function-box\">\n <div class=\"label-title\">\u51FD\u6570</div>\n <nz-input-group [nzSuffix]=\"suffixIconSearch\">\n <input type=\"text\" nz-input placeholder=\"\u641C\u7D22\" [(ngModel)]=\"searchFunction\" />\n </nz-input-group>\n <ng-template #suffixIconSearch>\n <i nz-icon nzType=\"search\"></i>\n </ng-template>\n <nz-tree\n class=\"function-tree\"\n [nzHideUnMatched]=\"true\"\n [nzSearchValue]=\"searchFunction()\"\n [nzTreeTemplate]=\"nzTreeTemplate\"\n [nzData]=\"funcNode\"\n [nzShowExpand]=\"functionListType() === _funcListType.Tree\"\n (nzClick)=\"functionClick($event)\"\n ></nz-tree>\n <ng-template #nzTreeTemplate let-node let-origin=\"origin\">\n <span class=\"custom-node\" [innerHTML]=\"origin.name | nzHighlight: searchFunction() : 'i' : 'node-highlight'\">\n @if (origin.description) {\n <span\n class=\"desc-icon\"\n nz-icon\n nzType=\"question-circle\"\n nzTheme=\"outline\"\n nz-tooltip\n [nzTooltipTitle]=\"origin.description\"\n ></span>\n }\n </span>\n </ng-template>\n </div>\n</div>\n", styles: [":host ::ng-deep .ant-tree-node-content-wrapper{width:100%}:host ::ng-deep .ant-input-affix-wrapper{padding:0 11px;height:32px}:host ::ng-deep .ProseMirror-focused{outline:none}:host ::ng-deep .node-highlight{color:#ff4d4f!important}:host .total-box{width:1000px;padding:8px;background-color:#fff}:host .ant-input-affix-wrapper{width:100%}:host .desc-icon{margin-left:auto}:host .formula-editor .editor-box{padding:12px;border-right:1px solid #e8e8e8}:host .formula-editor .editor-box .editor-title{display:flex;justify-content:space-between}:host .formula-editor .editor-box .edit-box{display:flex;flex-direction:column;height:400px;border:1px solid #ccc;border-radius:2px}:host .formula-editor .editor-box .edit-box .edit-operation-box{display:flex;gap:10px;align-items:center;height:32px;padding:0 10px;border-bottom:1px solid #ccc}:host .formula-editor .editor-box .edit-box .edit-operation-box .edit-operation-item{width:16px;height:16px;color:#687488;font-size:16px;line-height:16px;cursor:pointer;-webkit-user-select:none;user-select:none}:host .formula-editor .editor-box .edit-box .edit-operation-box .edit-operation-item .operator-icon{pointer-events:none}:host .formula-editor .editor-box .edit-box .edit-operation-box .edit-operation-item:hover .operator-icon{fill:#2e87ff}:host .formula-editor .editor-box .edit-box .edit-description-box{display:flex;flex-direction:column;padding:10px 10px 0;border-top:1px solid #ccc}:host .formula-editor .editor-box .edit-box .edit-description-box .edit-description-head{display:flex;justify-content:space-between}:host .formula-editor .editor-box .edit-box .edit-description-box .edit-description-text{max-height:128px;overflow:hidden auto;color:#333;font-size:13px;white-space:pre-wrap}:host .formula-editor .editor-box .edit-box .edit-description-box .edit-description-title{color:#333;font-weight:700;font-size:14px}:host .formula-editor .editor-box .edit-box .edit-description-box .edit-description-icon{font-size:14px;cursor:pointer}:host .formula-editor .editor-box .edit-box .edit-description-box .edit-description-icon:hover{color:#2e87ff}:host .formula-editor .editor-box .edit-box .editor{flex:1;min-height:0;padding:12px 10px;overflow:auto;font-size:13px}:host .formula-editor .metric-box{padding:12px}:host .formula-editor .metric-box .metric-list{display:flex;flex-direction:column;gap:4px;height:360px;margin-top:12px;overflow-y:auto}:host .formula-editor .metric-box .metric-list-item{display:flex;align-items:center;height:32px;min-height:32px;padding:0 12px;border:1px solid #ccc;border-radius:2px;cursor:pointer}:host .formula-editor .metric-box .metric-list-item:hover{background:#2e87ff1a;border:1px solid #2e87ff;border-radius:2px}:host .formula-editor .metric-box .metric-list-item .metric-img{width:24px;height:24px;margin-right:8px}:host .formula-editor .metric-box .metric-list-item .metric-icon{margin-right:4px;font-size:16px}:host .formula-editor .metric-box .metric-list-item .metric-name{flex:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}:host .formula-editor .field-box{padding:12px}:host .formula-editor .field-box .field-list{display:flex;flex-direction:column;gap:4px;height:360px;margin-top:12px;overflow-y:auto}:host .formula-editor .field-box .field-list-item{display:flex;flex-direction:row;align-items:center;height:32px;min-height:32px;padding:0 10px;border:1px solid #ccc;border-radius:2px;cursor:pointer}:host .formula-editor .field-box .field-list-item:hover{background:#2e87ff1a;border:1px solid #2e87ff;border-radius:2px}:host .formula-editor .field-box .field-list-item .field-img{width:24px;height:24px;margin-right:4px}:host .formula-editor .field-box .field-list-item .field-icon{margin-right:4px;font-size:16px}:host .formula-editor .field-box .field-list-item .field-name{flex:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}:host .formula-editor .function-box{padding:12px;border-left:1px solid #e8e8e8}:host .formula-editor .function-box .function-tree{height:360px;margin-top:8px;overflow-y:auto}:host .formula-editor .function-box .function-tree .custom-node{display:flex;align-items:center}:host .formula-editor .label-title{margin-bottom:12px;color:#333;font-weight:400;font-size:14px}:host .formula-editor .label-require:after{margin-left:4px;color:#f5222d;content:\"*\"}\n"], dependencies: [{ kind: "directive", type: 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: "ngmodule", type: NzGridModule }, { kind: "directive", type: i1.NzRowDirective, selector: "[nz-row],nz-row,nz-form-item", inputs: ["nzAlign", "nzJustify", "nzGutter"], exportAs: ["nzRow"] }, { kind: "ngmodule", type: NzInputModule }, { kind: "directive", type: i2.NzInputDirective, selector: "input[nz-input],textarea[nz-input]", inputs: ["nzBorderless", "nzSize", "nzStepperless", "nzStatus", "disabled"], exportAs: ["nzInput"] }, { kind: "component", type: i2.NzInputGroupComponent, selector: "nz-input-group", inputs: ["nzAddOnBeforeIcon", "nzAddOnAfterIcon", "nzPrefixIcon", "nzSuffixIcon", "nzAddOnBefore", "nzAddOnAfter", "nzPrefix", "nzStatus", "nzSuffix", "nzSize", "nzSearch", "nzCompact"], exportAs: ["nzInputGroup"] }, { kind: "directive", type: i2.NzInputGroupWhitSuffixOrPrefixDirective, selector: "nz-input-group[nzSuffix], nz-input-group[nzPrefix]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.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: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i4.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: NzTreeModule }, { kind: "component", type: i6.NzTreeComponent, selector: "nz-tree", inputs: ["nzShowIcon", "nzHideUnMatched", "nzBlockNode", "nzExpandAll", "nzSelectMode", "nzCheckStrictly", "nzShowExpand", "nzShowLine", "nzCheckable", "nzAsyncData", "nzDraggable", "nzMultiple", "nzExpandedIcon", "nzVirtualItemSize", "nzVirtualMaxBufferPx", "nzVirtualMinBufferPx", "nzVirtualHeight", "nzTreeTemplate", "nzBeforeDrop", "nzData", "nzExpandedKeys", "nzSelectedKeys", "nzCheckedKeys", "nzSearchValue", "nzSearchFunc"], outputs: ["nzExpandedKeysChange", "nzSelectedKeysChange", "nzCheckedKeysChange", "nzSearchValueChange", "nzClick", "nzDblClick", "nzContextMenu", "nzCheckBoxChange", "nzExpandChange", "nzOnDragStart", "nzOnDragEnter", "nzOnDragOver", "nzOnDragLeave", "nzOnDrop", "nzOnDragEnd"], exportAs: ["nzTree"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i7.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i8.ɵNzTransitionPatchDirective, selector: "[nz-button], nz-button-group, [nz-icon], [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "ngmodule", type: NzToolTipModule }, { kind: "directive", type: i9.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: "pipe", type: NzHighlightPipe, name: "nzHighlight" }] }); }
674
+ }
675
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FormulaEditorComponent, decorators: [{
676
+ type: Component,
677
+ args: [{ selector: 'app-formula-editor', standalone: true, imports: [
678
+ NzColDirective,
679
+ NzGridModule,
680
+ NzInputModule,
681
+ FormsModule,
682
+ NzIconModule,
683
+ CommonModule,
684
+ NzTreeModule,
685
+ NzButtonModule,
686
+ NzToolTipModule,
687
+ NzHighlightPipe
688
+ ], template: "<div nz-row class=\"formula-editor\">\n <div nz-col nzSpan=\"10\" class=\"editor-box\">\n <div class=\"editor-title\">\n <div class=\"label-title label-require\">\u5B57\u6BB5\u8868\u8FBE\u5F0F</div>\n <button nz-button nzType=\"link\" nzSize=\"small\" [nzLoading]=\"checkLoading\" (click)=\"checkFormat()\">\u683C\u5F0F\u6821\u9A8C</button>\n </div>\n <div class=\"edit-box\">\n <div class=\"edit-operation-box\">\n @for (item of _operatorList; track item) {\n <div class=\"edit-operation-item\" (click)=\"insertOperator(item.name)\">\n <span class=\"operator-icon\" [innerHTML]=\"getOperatorIcon(item.type)\"></span>\n </div>\n }\n </div>\n <div #editor class=\"editor\"></div>\n @if (editDescShow !== 'none') {\n <div class=\"edit-description-box\">\n <div class=\"edit-description-head\" [style]=\"{ marginBottom: !showDescription ? '10px' : '0' }\">\n <span class=\"edit-description-title\">{{ editDescShow === 'func' ? '\u51FD\u6570\u91CA\u4E49' : '\u6821\u9A8C\u9519\u8BEF\u4FE1\u606F' }}</span>\n <span\n class=\"edit-description-icon\"\n nz-icon\n [nzType]=\"showDescription ? 'down' : 'up'\"\n nzTheme=\"outline\"\n (click)=\"toggleDescription()\"\n ></span>\n </div>\n @if (showDescription) {\n <div class=\"edit-description-text\"> {{ editDescription }} </div>\n }\n </div>\n }\n </div>\n </div>\n @switch (itemType()) {\n @case (_itemType.Field) {\n <div nz-col nzSpan=\"7\" class=\"field-box\">\n <div class=\"label-title\"\n >{{ fieldTitle() }}\n @if (fieldDescription) {\n <span nz-icon nzType=\"question-circle\" nzTheme=\"outline\" nz-tooltip [nzTooltipTitle]=\"fieldDescription\"></span>\n }\n </div>\n <nz-input-group [nzSuffix]=\"suffixIconSearch\">\n <input type=\"text\" nz-input placeholder=\"\u641C\u7D22\" [(ngModel)]=\"searchField\" />\n </nz-input-group>\n <ng-template #suffixIconSearch>\n <i nz-icon nzType=\"search\"></i>\n </ng-template>\n <div class=\"field-list\">\n @for (item of fieldList; track item) {\n <div (click)=\"insertField(item)\" [class]=\"item.className ? 'item-field-' + item.className : ''\" class=\"field-list-item\">\n @if (item.image) {\n <img class=\"field-img\" [src]=\"item.image\" />\n }\n @if (item.icon) {\n <span class=\"field-icon\" nz-icon [nzIconfont]=\"item.icon\"></span>\n }\n <span class=\"field-name\" [innerHTML]=\"item.name | nzHighlight: searchField() : 'i' : 'node-highlight'\"></span>\n @if (item.description) {\n <span\n class=\"desc-icon\"\n nz-icon\n nzType=\"question-circle\"\n nzTheme=\"outline\"\n nz-tooltip\n [nzTooltipTitle]=\"item.description\"\n ></span>\n }\n </div>\n }\n </div>\n </div>\n }\n @case (_itemType.Template) {\n <div nz-col nzSpan=\"7\" class=\"field-box\">\n <ng-container *ngTemplateOutlet=\"itemTemplate()\"></ng-container>\n </div>\n }\n }\n <div nz-col nzSpan=\"7\" class=\"function-box\">\n <div class=\"label-title\">\u51FD\u6570</div>\n <nz-input-group [nzSuffix]=\"suffixIconSearch\">\n <input type=\"text\" nz-input placeholder=\"\u641C\u7D22\" [(ngModel)]=\"searchFunction\" />\n </nz-input-group>\n <ng-template #suffixIconSearch>\n <i nz-icon nzType=\"search\"></i>\n </ng-template>\n <nz-tree\n class=\"function-tree\"\n [nzHideUnMatched]=\"true\"\n [nzSearchValue]=\"searchFunction()\"\n [nzTreeTemplate]=\"nzTreeTemplate\"\n [nzData]=\"funcNode\"\n [nzShowExpand]=\"functionListType() === _funcListType.Tree\"\n (nzClick)=\"functionClick($event)\"\n ></nz-tree>\n <ng-template #nzTreeTemplate let-node let-origin=\"origin\">\n <span class=\"custom-node\" [innerHTML]=\"origin.name | nzHighlight: searchFunction() : 'i' : 'node-highlight'\">\n @if (origin.description) {\n <span\n class=\"desc-icon\"\n nz-icon\n nzType=\"question-circle\"\n nzTheme=\"outline\"\n nz-tooltip\n [nzTooltipTitle]=\"origin.description\"\n ></span>\n }\n </span>\n </ng-template>\n </div>\n</div>\n", styles: [":host ::ng-deep .ant-tree-node-content-wrapper{width:100%}:host ::ng-deep .ant-input-affix-wrapper{padding:0 11px;height:32px}:host ::ng-deep .ProseMirror-focused{outline:none}:host ::ng-deep .node-highlight{color:#ff4d4f!important}:host .total-box{width:1000px;padding:8px;background-color:#fff}:host .ant-input-affix-wrapper{width:100%}:host .desc-icon{margin-left:auto}:host .formula-editor .editor-box{padding:12px;border-right:1px solid #e8e8e8}:host .formula-editor .editor-box .editor-title{display:flex;justify-content:space-between}:host .formula-editor .editor-box .edit-box{display:flex;flex-direction:column;height:400px;border:1px solid #ccc;border-radius:2px}:host .formula-editor .editor-box .edit-box .edit-operation-box{display:flex;gap:10px;align-items:center;height:32px;padding:0 10px;border-bottom:1px solid #ccc}:host .formula-editor .editor-box .edit-box .edit-operation-box .edit-operation-item{width:16px;height:16px;color:#687488;font-size:16px;line-height:16px;cursor:pointer;-webkit-user-select:none;user-select:none}:host .formula-editor .editor-box .edit-box .edit-operation-box .edit-operation-item .operator-icon{pointer-events:none}:host .formula-editor .editor-box .edit-box .edit-operation-box .edit-operation-item:hover .operator-icon{fill:#2e87ff}:host .formula-editor .editor-box .edit-box .edit-description-box{display:flex;flex-direction:column;padding:10px 10px 0;border-top:1px solid #ccc}:host .formula-editor .editor-box .edit-box .edit-description-box .edit-description-head{display:flex;justify-content:space-between}:host .formula-editor .editor-box .edit-box .edit-description-box .edit-description-text{max-height:128px;overflow:hidden auto;color:#333;font-size:13px;white-space:pre-wrap}:host .formula-editor .editor-box .edit-box .edit-description-box .edit-description-title{color:#333;font-weight:700;font-size:14px}:host .formula-editor .editor-box .edit-box .edit-description-box .edit-description-icon{font-size:14px;cursor:pointer}:host .formula-editor .editor-box .edit-box .edit-description-box .edit-description-icon:hover{color:#2e87ff}:host .formula-editor .editor-box .edit-box .editor{flex:1;min-height:0;padding:12px 10px;overflow:auto;font-size:13px}:host .formula-editor .metric-box{padding:12px}:host .formula-editor .metric-box .metric-list{display:flex;flex-direction:column;gap:4px;height:360px;margin-top:12px;overflow-y:auto}:host .formula-editor .metric-box .metric-list-item{display:flex;align-items:center;height:32px;min-height:32px;padding:0 12px;border:1px solid #ccc;border-radius:2px;cursor:pointer}:host .formula-editor .metric-box .metric-list-item:hover{background:#2e87ff1a;border:1px solid #2e87ff;border-radius:2px}:host .formula-editor .metric-box .metric-list-item .metric-img{width:24px;height:24px;margin-right:8px}:host .formula-editor .metric-box .metric-list-item .metric-icon{margin-right:4px;font-size:16px}:host .formula-editor .metric-box .metric-list-item .metric-name{flex:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}:host .formula-editor .field-box{padding:12px}:host .formula-editor .field-box .field-list{display:flex;flex-direction:column;gap:4px;height:360px;margin-top:12px;overflow-y:auto}:host .formula-editor .field-box .field-list-item{display:flex;flex-direction:row;align-items:center;height:32px;min-height:32px;padding:0 10px;border:1px solid #ccc;border-radius:2px;cursor:pointer}:host .formula-editor .field-box .field-list-item:hover{background:#2e87ff1a;border:1px solid #2e87ff;border-radius:2px}:host .formula-editor .field-box .field-list-item .field-img{width:24px;height:24px;margin-right:4px}:host .formula-editor .field-box .field-list-item .field-icon{margin-right:4px;font-size:16px}:host .formula-editor .field-box .field-list-item .field-name{flex:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}:host .formula-editor .function-box{padding:12px;border-left:1px solid #e8e8e8}:host .formula-editor .function-box .function-tree{height:360px;margin-top:8px;overflow-y:auto}:host .formula-editor .function-box .function-tree .custom-node{display:flex;align-items:center}:host .formula-editor .label-title{margin-bottom:12px;color:#333;font-weight:400;font-size:14px}:host .formula-editor .label-require:after{margin-left:4px;color:#f5222d;content:\"*\"}\n"] }]
689
+ }], ctorParameters: () => [], propDecorators: { editor: [{
690
+ type: ViewChild,
691
+ args: ['editor']
692
+ }] } });
693
+
694
+ /**
695
+ * Generated bundle index. Do not edit.
696
+ */
697
+
698
+ export { CheckFormatMethod, FormulaEditorComponent, FormulaEditorRequestService, FormulaEditorRequestServiceToken, FormulaEditorService, FuncListType, ICONS, ItemType, OPERATOR_LIST };
699
+ //# sourceMappingURL=formula-editor.mjs.map