@yangyongtao/gaea 1.1.18 → 1.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/GaeaMethods.js +36 -3
- package/src/components/LayerTree.vue +359 -264
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.1.19] - 2026-07-13
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `GaeaApp.setCategoryVisible(key, visible)` / `getCategoryVisible(key)` — 按分类控制屏幕图标显隐
|
|
7
|
+
- `LayerTree` 每种分类左侧新增复选框,点击可切换该类图标的显示/隐藏
|
|
8
|
+
- `LayerTree` 所有核心样式通过 `--lt-*` CSS 变量暴露,消费者可在外部覆盖
|
|
9
|
+
|
|
3
10
|
## [1.1.18] - 2026-07-13
|
|
4
11
|
|
|
5
12
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yangyongtao/gaea",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.20",
|
|
4
4
|
"description": "Gaea 3D visualization component library - Vue 3 components based on Godot WASM engine. Includes WMTS layer loading, camera view control, Vite plugin auto-injection, etc.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.cjs",
|
package/src/GaeaMethods.js
CHANGED
|
@@ -822,6 +822,7 @@ export class GaeaApp {
|
|
|
822
822
|
visibleRange: cfg.visibleRange,
|
|
823
823
|
anchorType: cfg.anchorType,
|
|
824
824
|
drawLine: cfg.drawLine,
|
|
825
|
+
category: cat.key,
|
|
825
826
|
onClick: (name, data) => {
|
|
826
827
|
if (cfg.onClick) cfg.onClick(name, { ...child, ...data });
|
|
827
828
|
},
|
|
@@ -834,6 +835,38 @@ export class GaeaApp {
|
|
|
834
835
|
console.log('[GaeaApp] 屏幕图标创建完成, 共:', count);
|
|
835
836
|
}
|
|
836
837
|
|
|
838
|
+
// ---- 图层分类显隐控制 ----
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* 设置某个分类图标的可见性
|
|
842
|
+
* @param {string} categoryKey 分类 key(如 'seawall', 'hydrometricStations' 等)
|
|
843
|
+
* @param {boolean} visible 是否可见
|
|
844
|
+
*/
|
|
845
|
+
setCategoryVisible(categoryKey, visible) {
|
|
846
|
+
const items = this._screenIconList.filter(item => item.category === categoryKey);
|
|
847
|
+
if (!items.length) return;
|
|
848
|
+
items.forEach(item => {
|
|
849
|
+
if (visible) {
|
|
850
|
+
item.element.UseAutoVisible();
|
|
851
|
+
item.element.EnablePick = true;
|
|
852
|
+
} else {
|
|
853
|
+
item.element.ForceSetVisible(false);
|
|
854
|
+
item.element.EnablePick = false;
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
* 获取某个分类的当前可见性(根据第一个图标判断)
|
|
861
|
+
* @param {string} categoryKey
|
|
862
|
+
* @returns {boolean}
|
|
863
|
+
*/
|
|
864
|
+
getCategoryVisible(categoryKey) {
|
|
865
|
+
const item = this._screenIconList.find(item => item.category === categoryKey);
|
|
866
|
+
if (!item) return true;
|
|
867
|
+
return item.element.Visible !== false;
|
|
868
|
+
}
|
|
869
|
+
|
|
837
870
|
// ---- 公开方法 ----
|
|
838
871
|
|
|
839
872
|
/** 初始化默认图层和相机视角(手动调用,可传参覆盖配置) */
|
|
@@ -1176,7 +1209,7 @@ export class GaeaApp {
|
|
|
1176
1209
|
* 添加屏幕图标(参考 ht_3dview 三种创建方式)
|
|
1177
1210
|
* @param {string} opts.method - 'textImage' | 'styled' | 'imageOnly'
|
|
1178
1211
|
*/
|
|
1179
|
-
addScreenIcon({ name, text, imgUrl, position, method = 'textImage', offset = [0, 0], visibleRange = [10, 50000], anchorType = 6, drawLine = false, onClick, type = null, divId: externalDivId, elementName, elementChildrenIndex } = {}) {
|
|
1212
|
+
addScreenIcon({ name, text, imgUrl, position, method = 'textImage', offset = [0, 0], visibleRange = [10, 50000], anchorType = 6, drawLine = false, onClick, type = null, category = null, divId: externalDivId, elementName, elementChildrenIndex } = {}) {
|
|
1180
1213
|
const safeId = name.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '_');
|
|
1181
1214
|
const divId = externalDivId || 'gaea-icon-' + safeId;
|
|
1182
1215
|
|
|
@@ -1279,7 +1312,7 @@ export class GaeaApp {
|
|
|
1279
1312
|
console.log('[GaeaApp] child:', !!child);
|
|
1280
1313
|
if (child) {
|
|
1281
1314
|
child.AddChild(screen, false);
|
|
1282
|
-
const screenItem = { element: screen, type: type || null };
|
|
1315
|
+
const screenItem = { element: screen, type: type || null, category };
|
|
1283
1316
|
this._screenIconList.push(screenItem);
|
|
1284
1317
|
return screen;
|
|
1285
1318
|
}
|
|
@@ -1290,7 +1323,7 @@ export class GaeaApp {
|
|
|
1290
1323
|
|
|
1291
1324
|
screen.GeographyPosition = new Gaea.Vector3(position.x, position.y, position.z || 0);
|
|
1292
1325
|
Gaea.World.Instance.RenderableObjectList.AddLast(screen);
|
|
1293
|
-
const screenItem = { element: screen, type: type || null };
|
|
1326
|
+
const screenItem = { element: screen, type: type || null, category };
|
|
1294
1327
|
this._screenIconList.push(screenItem);
|
|
1295
1328
|
return screen;
|
|
1296
1329
|
}
|
|
@@ -1,264 +1,359 @@
|
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
</
|
|
30
|
-
</div>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
.
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
.
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
.
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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
|
+
<!-- 分类复选框 -->
|
|
21
|
+
<label class="category-checkbox" @click.stop>
|
|
22
|
+
<input
|
|
23
|
+
type="checkbox"
|
|
24
|
+
:checked="categoryVisibility[rootNode.key] !== false"
|
|
25
|
+
@change="onCategoryToggle(rootNode.key, $event.target.checked)"
|
|
26
|
+
/>
|
|
27
|
+
<span class="checkmark"></span>
|
|
28
|
+
</label>
|
|
29
|
+
<span class="node-text" :class="{ 'expanded-yellow': rootNode.isExpanded }">{{ rootNode.text }}</span>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div class="node-children" v-if="rootNode.isExpanded">
|
|
33
|
+
<div v-for="childNode in rootNode.filteredChildren" :key="childNode.text + (childNode.stcd || '')" class="child-node">
|
|
34
|
+
<div class="node-header" @click.stop="$emit('node-click', { category: rootNode, node: childNode })">
|
|
35
|
+
<span class="empty-icon"></span>
|
|
36
|
+
<span class="node-text">{{ childNode.text }}</span>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<script setup>
|
|
47
|
+
import { ref, onMounted, onBeforeUnmount, computed, reactive } from 'vue';
|
|
48
|
+
import vDrag from '../directives/vDrag.js';
|
|
49
|
+
|
|
50
|
+
const props = defineProps({
|
|
51
|
+
appInstance: { type: Object, required: true },
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const emit = defineEmits(['close', 'node-click']);
|
|
55
|
+
|
|
56
|
+
const categories = ref([]);
|
|
57
|
+
const searchKey = ref('');
|
|
58
|
+
const categoryVisibility = reactive({});
|
|
59
|
+
|
|
60
|
+
function handleHideLayerTree() {
|
|
61
|
+
emit('close');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
onMounted(() => {
|
|
65
|
+
const raw = props.appInstance?.layerCategories || [];
|
|
66
|
+
categories.value = raw
|
|
67
|
+
.filter(c => c.visible !== false)
|
|
68
|
+
.map(c => ({ ...c, isExpanded: false }));
|
|
69
|
+
// 初始化每个分类的可见性状态
|
|
70
|
+
for (const cat of categories.value) {
|
|
71
|
+
categoryVisibility[cat.key] = props.appInstance?.getCategoryVisible?.(cat.key) ?? true;
|
|
72
|
+
}
|
|
73
|
+
window.addEventListener('gaea-hide-layertree', handleHideLayerTree);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
onBeforeUnmount(() => {
|
|
77
|
+
window.removeEventListener('gaea-hide-layertree', handleHideLayerTree);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
function onCategoryToggle(categoryKey, checked) {
|
|
81
|
+
categoryVisibility[categoryKey] = checked;
|
|
82
|
+
props.appInstance?.setCategoryVisible?.(categoryKey, checked);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const filteredData = computed(() => {
|
|
86
|
+
const kw = searchKey.value.trim().toLowerCase();
|
|
87
|
+
return categories.value.map(rootNode => {
|
|
88
|
+
if (!kw) {
|
|
89
|
+
rootNode.filteredChildren = rootNode.children || [];
|
|
90
|
+
return rootNode;
|
|
91
|
+
}
|
|
92
|
+
const matchRoot = rootNode.text.toLowerCase().includes(kw);
|
|
93
|
+
const matchedChildren = (rootNode.children || []).filter(c => c.text.toLowerCase().includes(kw));
|
|
94
|
+
rootNode.filteredChildren = matchedChildren;
|
|
95
|
+
if (matchRoot || matchedChildren.length) return rootNode;
|
|
96
|
+
return null;
|
|
97
|
+
}).filter(Boolean);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
</script>
|
|
101
|
+
|
|
102
|
+
<style>
|
|
103
|
+
/* ===== CSS 变量暴露(消费者可覆盖) ===== */
|
|
104
|
+
:root {
|
|
105
|
+
--lt-bg: rgba(1, 79, 152, 0.85);
|
|
106
|
+
--lt-border-radius: 8px;
|
|
107
|
+
--lt-title-height: 42px;
|
|
108
|
+
--lt-title-color: #fff;
|
|
109
|
+
--lt-title-font-size: 20px;
|
|
110
|
+
--lt-close-color: #fff;
|
|
111
|
+
--lt-close-hover-color: #f0f9ff;
|
|
112
|
+
--lt-search-bg: rgba(0, 0, 0, 0.25);
|
|
113
|
+
--lt-search-color: #fff;
|
|
114
|
+
--lt-search-placeholder: #adb5bd;
|
|
115
|
+
--lt-node-color: #fff;
|
|
116
|
+
--lt-node-hover-bg: #007ffd;
|
|
117
|
+
--lt-node-expanded-color: #FDB144;
|
|
118
|
+
--lt-scrollbar-track: #f8f9fa;
|
|
119
|
+
--lt-scrollbar-thumb: #ced4da;
|
|
120
|
+
--lt-scrollbar-thumb-hover: #adb5bd;
|
|
121
|
+
--lt-child-border-color: #dee2e6;
|
|
122
|
+
--lt-checkbox-size: 16px;
|
|
123
|
+
--lt-checkbox-bg: rgba(255, 255, 255, 0.2);
|
|
124
|
+
--lt-checkbox-checked-bg: #3b82f6;
|
|
125
|
+
--lt-checkbox-border: rgba(255, 255, 255, 0.5);
|
|
126
|
+
}
|
|
127
|
+
</style>
|
|
128
|
+
|
|
129
|
+
<style scoped>
|
|
130
|
+
.layer-tree-dialog {
|
|
131
|
+
position: fixed;
|
|
132
|
+
top: 10px;
|
|
133
|
+
left: 10px;
|
|
134
|
+
width: 300px;
|
|
135
|
+
background: var(--lt-bg);
|
|
136
|
+
border-radius: var(--lt-border-radius);
|
|
137
|
+
overflow: hidden;
|
|
138
|
+
z-index: 10000;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.title {
|
|
142
|
+
height: var(--lt-title-height);
|
|
143
|
+
line-height: var(--lt-title-height);
|
|
144
|
+
padding: 0 14px;
|
|
145
|
+
color: var(--lt-title-color);
|
|
146
|
+
font-size: 15px;
|
|
147
|
+
font-weight: 500;
|
|
148
|
+
display: flex;
|
|
149
|
+
justify-content: space-between;
|
|
150
|
+
align-items: center;
|
|
151
|
+
cursor: move;
|
|
152
|
+
user-select: none;
|
|
153
|
+
background-size: 100% 100%;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.title .title_text {
|
|
157
|
+
font-size: var(--lt-title-font-size);
|
|
158
|
+
width: 100px;
|
|
159
|
+
text-align: left;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.closeIcon {
|
|
163
|
+
width: 22px;
|
|
164
|
+
height: 22px;
|
|
165
|
+
position: relative;
|
|
166
|
+
cursor: pointer;
|
|
167
|
+
transition: all 0.2s ease;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.closeIcon::before,
|
|
171
|
+
.closeIcon::after {
|
|
172
|
+
content: '';
|
|
173
|
+
position: absolute;
|
|
174
|
+
top: 25%;
|
|
175
|
+
left: 50%;
|
|
176
|
+
width: 14px;
|
|
177
|
+
height: 2px;
|
|
178
|
+
background-color: var(--lt-close-color);
|
|
179
|
+
border-radius: 1px;
|
|
180
|
+
transition: background-color 0.2s ease;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.closeIcon::before {
|
|
184
|
+
transform: translate(-50%, -50%) rotate(45deg);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.closeIcon::after {
|
|
188
|
+
transform: translate(-50%, -50%) rotate(-45deg);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.closeIcon:hover {
|
|
192
|
+
transform: scale(1.05);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.closeIcon:hover::before,
|
|
196
|
+
.closeIcon:hover::after {
|
|
197
|
+
background-color: var(--lt-close-hover-color);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.search-container {
|
|
201
|
+
padding: 10px 14px 0 14px;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.search-input {
|
|
205
|
+
width: 100%;
|
|
206
|
+
padding: 7px 12px;
|
|
207
|
+
border: none;
|
|
208
|
+
border-radius: 6px;
|
|
209
|
+
font-size: 14px;
|
|
210
|
+
outline: none;
|
|
211
|
+
box-sizing: border-box;
|
|
212
|
+
transition: all 0.2s ease;
|
|
213
|
+
background: var(--lt-search-bg);
|
|
214
|
+
color: var(--lt-search-color);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.search-input::placeholder {
|
|
218
|
+
color: var(--lt-search-placeholder);
|
|
219
|
+
font-size: 13px;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.layer-tree-container {
|
|
223
|
+
padding: 6px 0;
|
|
224
|
+
max-height: 390px;
|
|
225
|
+
overflow-y: auto;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.layer-tree-container::-webkit-scrollbar {
|
|
229
|
+
width: 5px;
|
|
230
|
+
height: 5px;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.layer-tree-container::-webkit-scrollbar-track {
|
|
234
|
+
background: var(--lt-scrollbar-track);
|
|
235
|
+
border-radius: 3px;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.layer-tree-container::-webkit-scrollbar-thumb {
|
|
239
|
+
background: var(--lt-scrollbar-thumb);
|
|
240
|
+
border-radius: 3px;
|
|
241
|
+
transition: background 0.2s ease;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.layer-tree-container::-webkit-scrollbar-thumb:hover {
|
|
245
|
+
background: var(--lt-scrollbar-thumb-hover);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.layer-tree-node {
|
|
249
|
+
margin-left: 6px;
|
|
250
|
+
line-height: 1.7;
|
|
251
|
+
color: var(--lt-node-color);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.node-header {
|
|
255
|
+
display: flex;
|
|
256
|
+
align-items: center;
|
|
257
|
+
gap: 5px;
|
|
258
|
+
padding: 3px 8px;
|
|
259
|
+
border-radius: 4px;
|
|
260
|
+
cursor: pointer;
|
|
261
|
+
transition: background-color 0.15s ease;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.node-header:hover {
|
|
265
|
+
background-color: var(--lt-node-hover-bg);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.expand-icon {
|
|
269
|
+
font-size: 11px;
|
|
270
|
+
color: #6c757d;
|
|
271
|
+
width: 12px;
|
|
272
|
+
height: 12px;
|
|
273
|
+
text-align: center;
|
|
274
|
+
user-select: none;
|
|
275
|
+
cursor: pointer;
|
|
276
|
+
flex-shrink: 0;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.empty-icon {
|
|
280
|
+
width: 12px;
|
|
281
|
+
height: 12px;
|
|
282
|
+
display: inline-block;
|
|
283
|
+
flex-shrink: 0;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.node-icon {
|
|
287
|
+
font-size: 13px;
|
|
288
|
+
width: 14px;
|
|
289
|
+
text-align: center;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.node-text {
|
|
293
|
+
flex: 1;
|
|
294
|
+
font-size: 13.5px;
|
|
295
|
+
text-align: left;
|
|
296
|
+
transition: color 0.15s ease;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.expanded-yellow {
|
|
300
|
+
color: var(--lt-node-expanded-color) !important;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.node-children {
|
|
304
|
+
margin-left: 14px;
|
|
305
|
+
padding-left: 4px;
|
|
306
|
+
border-left: 1px dashed var(--lt-child-border-color);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.child-node {
|
|
310
|
+
margin-left: 2px;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/* ===== 分类复选框 ===== */
|
|
314
|
+
.category-checkbox {
|
|
315
|
+
position: relative;
|
|
316
|
+
display: inline-flex;
|
|
317
|
+
align-items: center;
|
|
318
|
+
justify-content: center;
|
|
319
|
+
width: var(--lt-checkbox-size);
|
|
320
|
+
height: var(--lt-checkbox-size);
|
|
321
|
+
flex-shrink: 0;
|
|
322
|
+
cursor: pointer;
|
|
323
|
+
user-select: none;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.category-checkbox input[type="checkbox"] {
|
|
327
|
+
position: absolute;
|
|
328
|
+
opacity: 0;
|
|
329
|
+
width: 0;
|
|
330
|
+
height: 0;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.checkmark {
|
|
334
|
+
width: 100%;
|
|
335
|
+
height: 100%;
|
|
336
|
+
border: 1.5px solid var(--lt-checkbox-border);
|
|
337
|
+
border-radius: 3px;
|
|
338
|
+
background: var(--lt-checkbox-bg);
|
|
339
|
+
display: flex;
|
|
340
|
+
align-items: center;
|
|
341
|
+
justify-content: center;
|
|
342
|
+
transition: all 0.15s ease;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.category-checkbox input:checked + .checkmark {
|
|
346
|
+
background: var(--lt-checkbox-checked-bg);
|
|
347
|
+
border-color: var(--lt-checkbox-checked-bg);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.category-checkbox input:checked + .checkmark::after {
|
|
351
|
+
content: '';
|
|
352
|
+
width: 4px;
|
|
353
|
+
height: 8px;
|
|
354
|
+
border: solid #fff;
|
|
355
|
+
border-width: 0 2px 2px 0;
|
|
356
|
+
transform: rotate(45deg);
|
|
357
|
+
margin-top: -1px;
|
|
358
|
+
}
|
|
359
|
+
</style>
|