@yangyongtao/gaea 1.1.9 → 1.1.11

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,435 @@
1
+ <template>
2
+ <CommonDialog
3
+ :modelValue="show"
4
+ :title="title"
5
+ :showFooter="false"
6
+ closable
7
+ @close="show = false"
8
+ @update:modelValue="show = $event"
9
+ >
10
+ <div class="hydrologic-container">
11
+ <!-- 图表模式 -->
12
+ <div v-show="tab === 'chart'">
13
+ <div class="hydrologic-stat-bar">
14
+ <div class="stat-item">
15
+ <span class="stat-label">累计雨量</span>
16
+ <span class="stat-value">{{ totalRain.toFixed(1) }}</span>
17
+ <span class="stat-unit">mm</span>
18
+ </div>
19
+ <div class="stat-item">
20
+ <span class="stat-label">当前水位</span>
21
+ <span class="stat-value">{{ waterLevel.toFixed(2) }}</span>
22
+ <span class="stat-unit">m</span>
23
+ </div>
24
+ </div>
25
+ <div class="second-row">
26
+ <div class="time-range-area">
27
+ <div class="time-range-tabs">
28
+ <span class="time-tab" :class="{ active: timeRange === '24h' }" @click="switchRange('24h')">前24小时</span>
29
+ <span class="time-tab" :class="{ active: timeRange === '48h' }" @click="switchRange('48h')">前48小时</span>
30
+ <span class="time-tab" :class="{ active: timeRange === '72h' }" @click="switchRange('72h')">前72小时</span>
31
+ <span class="time-tab" :class="{ active: timeRange === 'custom' }" @click="timeRange = 'custom'">自定义</span>
32
+ <div class="custom-time-picker" v-show="timeRange === 'custom'">
33
+ <input type="datetime-local" v-model="customStartTime" class="custom-input" />
34
+ <span class="time-separator">至</span>
35
+ <input type="datetime-local" v-model="customEndTime" class="custom-input" />
36
+ <button class="query-btn" @click="queryCustomTimeRange">查询</button>
37
+ </div>
38
+ </div>
39
+ </div>
40
+ <div class="tab-switch">
41
+ <span class="tab-item" :class="{ active: tab === 'chart' }" @click="tab = 'chart'">图表</span>
42
+ <span class="tab-item" :class="{ active: tab === 'table' }" @click="tab = 'table'">表格</span>
43
+ </div>
44
+ </div>
45
+ </div>
46
+ <!-- 表格模式 -->
47
+ <div v-show="tab === 'table'" class="table-header">
48
+ <div class="tab-switch">
49
+ <span class="tab-item" :class="{ active: tab === 'chart' }" @click="tab = 'chart'">图表</span>
50
+ <span class="tab-item" :class="{ active: tab === 'table' }" @click="tab = 'table'">表格</span>
51
+ </div>
52
+ </div>
53
+ <!-- 内容区域 -->
54
+ <div class="content-area">
55
+ <div class="hydrologic-charts" v-show="tab === 'chart'">
56
+ <div class="chart-box" ref="chartRef"></div>
57
+ </div>
58
+ <div class="table-section" v-show="tab === 'table'">
59
+ <table class="hydrologic-table">
60
+ <thead>
61
+ <tr>
62
+ <th>时间</th>
63
+ <th>雨量 (mm)</th>
64
+ <th>水位 (m)</th>
65
+ <th>流量 (m³/s)</th>
66
+ </tr>
67
+ </thead>
68
+ <tbody>
69
+ <tr v-for="(row, idx) in tableData" :key="idx">
70
+ <td>{{ row.time }}</td>
71
+ <td>{{ row.rain }}</td>
72
+ <td>{{ row.waterLevel }}</td>
73
+ <td>{{ row.flow }}</td>
74
+ </tr>
75
+ </tbody>
76
+ </table>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ </CommonDialog>
81
+ </template>
82
+
83
+ <script setup>
84
+ import { ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue';
85
+ import CommonDialog from './CommonDialog.vue';
86
+
87
+ const show = ref(false);
88
+ const title = ref('');
89
+ const tab = ref('chart');
90
+ const timeRange = ref('24h');
91
+ const totalRain = ref(0);
92
+ const waterLevel = ref(0);
93
+ const tableData = ref([]);
94
+ const customStartTime = ref('');
95
+ const customEndTime = ref('');
96
+ const chartRef = ref(null);
97
+ let chartInstance = null;
98
+ let echartsModule = null;
99
+
100
+ function fmt(d) {
101
+ const mm = String(d.getMonth() + 1).padStart(2, '0');
102
+ const dd = String(d.getDate()).padStart(2, '0');
103
+ const hh = String(d.getHours()).padStart(2, '0');
104
+ return `${mm}-${dd} ${hh}:00`;
105
+ }
106
+
107
+ function genData(count) {
108
+ const now = new Date();
109
+ const hours = [];
110
+ const rainValues = [];
111
+ const waterLevels = [];
112
+ const flowValues = [];
113
+ const table = [];
114
+ for (let i = count - 1; i >= 0; i--) {
115
+ const t = new Date(now.getTime() - i * 3600000);
116
+ const timeStr = fmt(t);
117
+ hours.push(timeStr);
118
+ const rain = +(Math.random() * 20).toFixed(1);
119
+ const wl = +(10 + Math.random() * 20).toFixed(2);
120
+ const flow = +(50 + Math.random() * 250).toFixed(1);
121
+ rainValues.push(rain);
122
+ waterLevels.push(wl);
123
+ flowValues.push(flow);
124
+ table.push({ time: timeStr, rain, waterLevel: wl, flow });
125
+ }
126
+ return { hours, rainValues, waterLevels, flowValues, table };
127
+ }
128
+
129
+ function getChartOption(hours, rainValues, waterLevels, flowValues) {
130
+ return {
131
+ tooltip: { trigger: 'axis' },
132
+ legend: { data: ['雨量', '水位', '流量'], top: 5, textStyle: { color: '#fff', fontSize: 11 } },
133
+ grid: [
134
+ { top: 45, right: 60, bottom: '58%', left: 50 },
135
+ { top: '50%', right: 100, bottom: 40, left: 50 },
136
+ ],
137
+ xAxis: [
138
+ { type: 'category', data: hours, gridIndex: 0, axisLabel: { show: false }, axisTick: { show: false }, axisLine: { show: false } },
139
+ { type: 'category', data: hours, gridIndex: 1 },
140
+ ],
141
+ yAxis: [
142
+ { type: 'value', name: '雨量 (mm)', gridIndex: 0, inverse: true, nameLocation: 'middle', nameRotate: 90, nameTextStyle: { color: '#8AB8E6', fontSize: 11 } },
143
+ { type: 'value', name: '水位(m)', gridIndex: 1, nameLocation: 'middle', nameRotate: 90, nameTextStyle: { color: '#8AB8E6', fontSize: 11 } },
144
+ { type: 'value', name: '流量(m³/s)', gridIndex: 1, position: 'right', offset: 60, nameLocation: 'middle', nameRotate: 90, nameTextStyle: { color: '#8AB8E6', fontSize: 11 } },
145
+ ],
146
+ series: [
147
+ { name: '雨量', type: 'bar', data: rainValues, xAxisIndex: 0, yAxisIndex: 0 },
148
+ { name: '水位', type: 'line', data: waterLevels, xAxisIndex: 1, yAxisIndex: 1 },
149
+ { name: '流量', type: 'line', data: flowValues, xAxisIndex: 1, yAxisIndex: 2 },
150
+ ],
151
+ };
152
+ }
153
+
154
+ function updateData(count) {
155
+ const { hours, rainValues, waterLevels, flowValues, table } = genData(count);
156
+ totalRain.value = rainValues.reduce((sum, v) => sum + parseFloat(v), 0);
157
+ waterLevel.value = waterLevels[waterLevels.length - 1] || 0;
158
+ tableData.value = table;
159
+ if (chartInstance) {
160
+ chartInstance.setOption(getChartOption(hours, rainValues, waterLevels, flowValues), true);
161
+ }
162
+ }
163
+
164
+ function switchRange(range) {
165
+ timeRange.value = range;
166
+ }
167
+
168
+ function queryCustomTimeRange() {
169
+ if (!customStartTime.value || !customEndTime.value) return;
170
+ const start = new Date(customStartTime.value);
171
+ const end = new Date(customEndTime.value);
172
+ if (end <= start) return;
173
+ const hours = [];
174
+ const rainValues = [];
175
+ const waterLevels = [];
176
+ const flowValues = [];
177
+ const table = [];
178
+ let cur = new Date(start);
179
+ while (cur <= end) {
180
+ const timeStr = fmt(cur);
181
+ hours.push(timeStr);
182
+ const rain = +(Math.random() * 20).toFixed(1);
183
+ const wl = +(10 + Math.random() * 20).toFixed(2);
184
+ const flow = +(50 + Math.random() * 250).toFixed(1);
185
+ rainValues.push(rain);
186
+ waterLevels.push(wl);
187
+ flowValues.push(flow);
188
+ table.push({ time: timeStr, rain, waterLevel: wl, flow });
189
+ cur = new Date(cur.getTime() + 3600000);
190
+ }
191
+ totalRain.value = rainValues.reduce((sum, v) => sum + parseFloat(v), 0);
192
+ waterLevel.value = waterLevels[waterLevels.length - 1] || 0;
193
+ tableData.value = table;
194
+ if (chartInstance) {
195
+ chartInstance.setOption(getChartOption(hours, rainValues, waterLevels, flowValues), true);
196
+ }
197
+ }
198
+
199
+ watch(timeRange, (r) => {
200
+ if (r === 'custom') return;
201
+ const map = { '24h': 24, '48h': 48, '72h': 72 };
202
+ updateData(map[r] || 24);
203
+ });
204
+
205
+ function handleIconClick(event) {
206
+ const detail = event.detail || event;
207
+ if (detail.category !== 'hydrometricStations') return;
208
+ title.value = detail.name;
209
+ tab.value = 'chart';
210
+ timeRange.value = '24h';
211
+ show.value = true;
212
+ nextTick(async () => {
213
+ if (!echartsModule) {
214
+ echartsModule = (await import('echarts')).default || (await import('echarts'));
215
+ }
216
+ if (chartRef.value && !chartInstance) {
217
+ chartInstance = echartsModule.init(chartRef.value);
218
+ }
219
+ updateData(24);
220
+ });
221
+ }
222
+
223
+ onBeforeUnmount(() => {
224
+ window.removeEventListener('gaea-icon-click', handleIconClick);
225
+ if (chartInstance) { chartInstance.dispose(); chartInstance = null; }
226
+ });
227
+
228
+ onMounted(() => {
229
+ window.addEventListener('gaea-icon-click', handleIconClick);
230
+ });
231
+ </script>
232
+
233
+ <style scoped>
234
+ .hydrologic-container {
235
+ display: flex;
236
+ flex-direction: column;
237
+ flex: 1;
238
+ min-height: 0;
239
+ }
240
+
241
+ .hydrologic-stat-bar {
242
+ background-image: linear-gradient(269deg, rgba(0, 135, 255, 0) 2%, rgba(0, 130, 255, 0.26) 100%);
243
+ border-radius: 4px 2px 2px 4px;
244
+ padding: 8px 14px;
245
+ flex-shrink: 0;
246
+ display: flex;
247
+ justify-content: space-around;
248
+ }
249
+ .stat-item {
250
+ display: flex;
251
+ align-items: center;
252
+ gap: 10px;
253
+ }
254
+ .stat-label {
255
+ color: #A8D4FF;
256
+ font-size: 14px;
257
+ }
258
+ .stat-value {
259
+ color: #00D2FF;
260
+ font-size: 18px;
261
+ font-weight: bold;
262
+ }
263
+ .stat-unit {
264
+ color: #8AB8E6;
265
+ font-size: 13px;
266
+ margin-left: -6px;
267
+ }
268
+
269
+ .second-row {
270
+ display: flex;
271
+ justify-content: space-between;
272
+ align-items: center;
273
+ margin-top: 8px;
274
+ padding-bottom: 8px;
275
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
276
+ }
277
+ .time-range-area {
278
+ display: flex;
279
+ align-items: center;
280
+ }
281
+ .time-range-tabs {
282
+ display: flex;
283
+ align-items: center;
284
+ gap: 6px;
285
+ }
286
+ .custom-time-picker {
287
+ display: flex;
288
+ align-items: center;
289
+ gap: 8px;
290
+ margin-left: 8px;
291
+ padding-left: 8px;
292
+ border-left: 1px solid rgba(255, 255, 255, 0.1);
293
+ }
294
+ .custom-input {
295
+ width: 150px;
296
+ padding: 4px 8px;
297
+ background: rgba(0, 102, 204, 0.2);
298
+ border: 1px solid rgba(0, 102, 204, 0.5);
299
+ color: #fff;
300
+ font-size: 12px;
301
+ border-radius: 3px;
302
+ outline: none;
303
+ }
304
+ .custom-input:focus {
305
+ border-color: #00D2FF;
306
+ }
307
+ .time-separator {
308
+ color: #8AB8E6;
309
+ font-size: 12px;
310
+ }
311
+ .query-btn {
312
+ background: rgba(0, 102, 204, 0.4);
313
+ border: 1px solid #0066CC;
314
+ color: #00D2FF;
315
+ font-size: 12px;
316
+ padding: 4px 14px;
317
+ border-radius: 3px;
318
+ cursor: pointer;
319
+ transition: all 0.2s;
320
+ }
321
+ .query-btn:hover {
322
+ background: rgba(0, 102, 204, 0.6);
323
+ border-color: #00D2FF;
324
+ }
325
+
326
+ .time-tab {
327
+ padding: 4px 12px;
328
+ font-size: 12px;
329
+ color: #8AB8E6;
330
+ border: 1px solid rgba(255, 255, 255, 0.1);
331
+ border-radius: 3px;
332
+ cursor: pointer;
333
+ transition: all 0.2s;
334
+ user-select: none;
335
+ }
336
+ .time-tab:hover {
337
+ border-color: #0066CC;
338
+ color: #fff;
339
+ }
340
+ .time-tab.active {
341
+ background: rgba(0, 102, 204, 0.4);
342
+ border-color: #0066CC;
343
+ color: #00D2FF;
344
+ }
345
+
346
+ .tab-switch {
347
+ display: flex;
348
+ gap: 4px;
349
+ margin-bottom: 6px;
350
+ flex-shrink: 0;
351
+ }
352
+ .tab-item {
353
+ padding: 4px 18px;
354
+ font-size: 13px;
355
+ color: #8AB8E6;
356
+ border: 1px solid rgba(255, 255, 255, 0.15);
357
+ border-radius: 4px;
358
+ cursor: pointer;
359
+ transition: all 0.2s;
360
+ user-select: none;
361
+ }
362
+ .tab-item:hover {
363
+ border-color: #0066CC;
364
+ color: #fff;
365
+ }
366
+ .tab-item.active {
367
+ background: rgba(0, 102, 204, 0.3);
368
+ border-color: #0066CC;
369
+ color: #00D2FF;
370
+ }
371
+
372
+ .table-header {
373
+ padding: 8px 0;
374
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
375
+ }
376
+
377
+ .content-area {
378
+ flex: 1;
379
+ min-height: 0;
380
+ display: flex;
381
+ flex-direction: column;
382
+ }
383
+
384
+ .hydrologic-charts {
385
+ display: flex;
386
+ flex-direction: column;
387
+ flex: 1;
388
+ min-height: 0;
389
+ }
390
+
391
+ .chart-box {
392
+ width: 100%;
393
+ flex: 1;
394
+ min-height: 0;
395
+ }
396
+
397
+ .table-section {
398
+ flex: 1;
399
+ overflow-y: auto;
400
+ position: relative;
401
+ }
402
+
403
+ .table-section::-webkit-scrollbar {
404
+ width: 4px;
405
+ }
406
+ .table-section::-webkit-scrollbar-thumb {
407
+ background: #0088FF;
408
+ border-radius: 2px;
409
+ }
410
+
411
+ .hydrologic-table {
412
+ width: 100%;
413
+ border-collapse: collapse;
414
+ color: #8AB8E6;
415
+ font-size: 13px;
416
+ }
417
+ .hydrologic-table th,
418
+ .hydrologic-table td {
419
+ padding: 8px 12px;
420
+ text-align: center;
421
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
422
+ }
423
+ .hydrologic-table th {
424
+ color: #00D2FF;
425
+ font-weight: bold;
426
+ background: rgba(0, 30, 60, 0.95);
427
+ position: sticky;
428
+ top: 0;
429
+ z-index: 1;
430
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
431
+ }
432
+ .hydrologic-table tbody tr:hover {
433
+ background: rgba(0, 102, 204, 0.1);
434
+ }
435
+ </style>
@@ -0,0 +1,264 @@
1
+ <template>
2
+ <div class="layer-tree-dialog" v-drag>
3
+ <div class="title">
4
+ <div class="title_text">图层控制</div>
5
+ <div class="closeIcon" @click="$emit('close')"></div>
6
+ </div>
7
+
8
+ <div class="search-container">
9
+ <input type="text" class="search-input" v-model="searchKey" placeholder="搜索图层..." />
10
+ </div>
11
+
12
+ <div class="layer-tree-container">
13
+ <div class="layer-tree-content">
14
+ <div v-for="rootNode in filteredData" :key="rootNode.key" class="layer-tree-node">
15
+ <div class="node-header" @click.stop="rootNode.isExpanded = !rootNode.isExpanded">
16
+ <span class="expand-icon">
17
+ <span v-if="!rootNode.isExpanded">▸</span>
18
+ <span v-else>▾</span>
19
+ </span>
20
+ <span class="node-text" :class="{ 'expanded-yellow': rootNode.isExpanded }">{{ rootNode.text }}</span>
21
+ </div>
22
+
23
+ <div class="node-children" v-if="rootNode.isExpanded">
24
+ <div v-for="childNode in rootNode.filteredChildren" :key="childNode.text + (childNode.stcd || '')" class="child-node">
25
+ <div class="node-header" @click.stop="$emit('node-click', { category: rootNode, node: childNode })">
26
+ <span class="empty-icon"></span>
27
+ <span class="node-text">{{ childNode.text }}</span>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ </template>
36
+
37
+ <script setup>
38
+ import { ref, onMounted, onBeforeUnmount, computed } from 'vue';
39
+ import vDrag from '../directives/vDrag.js';
40
+
41
+ const props = defineProps({
42
+ appInstance: { type: Object, required: true },
43
+ });
44
+
45
+ const emit = defineEmits(['close', 'node-click']);
46
+
47
+ const categories = ref([]);
48
+ const searchKey = ref('');
49
+
50
+ function handleHideLayerTree() {
51
+ emit('close');
52
+ }
53
+
54
+ onMounted(() => {
55
+ const raw = props.appInstance?.layerCategories || [];
56
+ categories.value = raw
57
+ .filter(c => c.visible !== false)
58
+ .map(c => ({ ...c, isExpanded: false }));
59
+ window.addEventListener('gaea-hide-layertree', handleHideLayerTree);
60
+ });
61
+
62
+ onBeforeUnmount(() => {
63
+ window.removeEventListener('gaea-hide-layertree', handleHideLayerTree);
64
+ });
65
+
66
+ const filteredData = computed(() => {
67
+ const kw = searchKey.value.trim().toLowerCase();
68
+ return categories.value.map(rootNode => {
69
+ if (!kw) {
70
+ rootNode.filteredChildren = rootNode.children || [];
71
+ return rootNode;
72
+ }
73
+ const matchRoot = rootNode.text.toLowerCase().includes(kw);
74
+ const matchedChildren = (rootNode.children || []).filter(c => c.text.toLowerCase().includes(kw));
75
+ rootNode.filteredChildren = matchedChildren;
76
+ if (matchRoot || matchedChildren.length) return rootNode;
77
+ return null;
78
+ }).filter(Boolean);
79
+ });
80
+
81
+ </script>
82
+
83
+ <style scoped>
84
+ .layer-tree-dialog {
85
+ position: fixed;
86
+ top: 10px;
87
+ left: 10px;
88
+ width: 300px;
89
+ background: rgba(1, 79, 152, 0.85);
90
+ border-radius: 8px;
91
+ overflow: hidden;
92
+ z-index: 10000;
93
+ }
94
+
95
+ .title {
96
+ height: 42px;
97
+ line-height: 42px;
98
+ padding: 0 14px;
99
+ color: #fff;
100
+ font-size: 15px;
101
+ font-weight: 500;
102
+ display: flex;
103
+ justify-content: space-between;
104
+ align-items: center;
105
+ cursor: move;
106
+ user-select: none;
107
+ background-size: 100% 100%;
108
+ }
109
+
110
+ .title .title_text {
111
+ font-size: 20px;
112
+ width: 100px;
113
+ text-align: left;
114
+ }
115
+
116
+ .closeIcon {
117
+ width: 22px;
118
+ height: 22px;
119
+ position: relative;
120
+ cursor: pointer;
121
+ transition: all 0.2s ease;
122
+ }
123
+
124
+ .closeIcon::before,
125
+ .closeIcon::after {
126
+ content: '';
127
+ position: absolute;
128
+ top: 25%;
129
+ left: 50%;
130
+ width: 14px;
131
+ height: 2px;
132
+ background-color: #fff;
133
+ border-radius: 1px;
134
+ transition: background-color 0.2s ease;
135
+ }
136
+
137
+ .closeIcon::before {
138
+ transform: translate(-50%, -50%) rotate(45deg);
139
+ }
140
+
141
+ .closeIcon::after {
142
+ transform: translate(-50%, -50%) rotate(-45deg);
143
+ }
144
+
145
+ .closeIcon:hover {
146
+ transform: scale(1.05);
147
+ }
148
+
149
+ .closeIcon:hover::before,
150
+ .closeIcon:hover::after {
151
+ background-color: #f0f9ff;
152
+ }
153
+
154
+ .search-container {
155
+ padding: 10px 14px 0 14px;
156
+ }
157
+
158
+ .search-input {
159
+ width: 100%;
160
+ padding: 7px 12px;
161
+ border: none;
162
+ border-radius: 6px;
163
+ font-size: 14px;
164
+ outline: none;
165
+ box-sizing: border-box;
166
+ transition: all 0.2s ease;
167
+ background: rgba(0,0,0,0.25);
168
+ color: #fff;
169
+ }
170
+
171
+ .search-input::placeholder {
172
+ color: #adb5bd;
173
+ font-size: 13px;
174
+ }
175
+
176
+ .layer-tree-container {
177
+ padding: 6px 0;
178
+ max-height: 390px;
179
+ overflow-y: auto;
180
+ }
181
+
182
+ .layer-tree-container::-webkit-scrollbar {
183
+ width: 5px;
184
+ height: 5px;
185
+ }
186
+
187
+ .layer-tree-container::-webkit-scrollbar-track {
188
+ background: #f8f9fa;
189
+ border-radius: 3px;
190
+ }
191
+
192
+ .layer-tree-container::-webkit-scrollbar-thumb {
193
+ background: #ced4da;
194
+ border-radius: 3px;
195
+ transition: background 0.2s ease;
196
+ }
197
+
198
+ .layer-tree-container::-webkit-scrollbar-thumb:hover {
199
+ background: #adb5bd;
200
+ }
201
+
202
+ .layer-tree-node {
203
+ margin-left: 6px;
204
+ line-height: 1.7;
205
+ color: #fff;
206
+ }
207
+
208
+ .node-header {
209
+ display: flex;
210
+ align-items: center;
211
+ gap: 5px;
212
+ padding: 3px 8px;
213
+ border-radius: 4px;
214
+ cursor: pointer;
215
+ transition: background-color 0.15s ease;
216
+ }
217
+
218
+ .node-header:hover {
219
+ background-color: #007ffd;
220
+ }
221
+
222
+ .expand-icon {
223
+ font-size: 11px;
224
+ color: #6c757d;
225
+ width: 12px;
226
+ height: 12px;
227
+ text-align: center;
228
+ user-select: none;
229
+ cursor: pointer;
230
+ }
231
+
232
+ .empty-icon {
233
+ width: 12px;
234
+ height: 12px;
235
+ display: inline-block;
236
+ }
237
+
238
+ .node-icon {
239
+ font-size: 13px;
240
+ width: 14px;
241
+ text-align: center;
242
+ }
243
+
244
+ .node-text {
245
+ flex: 1;
246
+ font-size: 13.5px;
247
+ text-align: left;
248
+ transition: color 0.15s ease;
249
+ }
250
+
251
+ .expanded-yellow {
252
+ color: #FDB144 !important;
253
+ }
254
+
255
+ .node-children {
256
+ margin-left: 14px;
257
+ padding-left: 4px;
258
+ border-left: 1px dashed #dee2e6;
259
+ }
260
+
261
+ .child-node {
262
+ margin-left: 2px;
263
+ }
264
+ </style>