st-comp 0.0.239 → 0.0.242
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/components.d.ts +1 -0
- package/es/CustomFunction.cjs +1 -1
- package/es/CustomFunction.js +21 -21
- package/es/FactorWarning.cjs +1 -1
- package/es/FactorWarning.js +25 -25
- package/es/Kline.cjs +1 -1
- package/es/Kline.js +10 -10
- package/es/KlineBasic.cjs +1 -1
- package/es/KlineBasic.js +18 -18
- package/es/KlineConfig.cjs +1 -1
- package/es/KlineConfig.js +15 -15
- package/es/KlineNew.cjs +1 -1
- package/es/KlineNew.js +9 -9
- package/es/KlinePlus.cjs +1 -1
- package/es/KlinePlus.js +11 -11
- package/es/MonacoEditor.cjs +1 -1
- package/es/MonacoEditor.js +31 -3
- package/es/Pagination.cjs +1 -1
- package/es/Pagination.js +13 -13
- package/es/PasswordPrompt.cjs +1 -1
- package/es/PasswordPrompt.js +2 -2
- package/es/Table.cjs +1 -1
- package/es/Table.js +17 -17
- package/es/User.cjs +1 -1
- package/es/User.js +18 -18
- package/es/VarSelectDialog.cjs +3 -3
- package/es/VarSelectDialog.js +122 -178
- package/es/VarietyAutoComplete.cjs +1 -1
- package/es/VarietyAutoComplete.js +7 -7
- package/es/VarietySearch.cjs +20 -19
- package/es/VarietySearch.js +2943 -2740
- package/es/VarietySelect-2fd501da.cjs +1 -0
- package/es/VarietySelect-5a9dd50b.js +68 -0
- package/es/VarietyTextCopy.cjs +1 -1
- package/es/VarietyTextCopy.js +9 -9
- package/es/VirtualTable.cjs +1 -1
- package/es/VirtualTable.js +61 -61
- package/es/{_initCloneObject-52b6a510.cjs → _initCloneObject-3823a101.cjs} +1 -1
- package/es/{_initCloneObject-eaef9418.js → _initCloneObject-c34c65bc.js} +2 -2
- package/es/{config-provider-b16efd62.js → config-provider-06a63185.js} +3 -3
- package/es/{config-provider-a584d81e.cjs → config-provider-2182708a.cjs} +1 -1
- package/es/{dropdown-a59bba73.js → dropdown-302f71e7.js} +2 -2
- package/es/{dropdown-071c5d7e.cjs → dropdown-89b74bc9.cjs} +1 -1
- package/es/{el-autocomplete-a07e9439.cjs → el-autocomplete-b9a3054a.cjs} +1 -1
- package/es/{el-autocomplete-ba808eb6.js → el-autocomplete-ed75a659.js} +5 -5
- package/es/{el-button-eec58cff.cjs → el-button-68baab7b.cjs} +1 -1
- package/es/{el-button-c95adb85.js → el-button-d09ff85f.js} +3 -3
- package/es/{el-checkbox-7421ccd3.js → el-checkbox-64648e02.js} +3 -3
- package/es/{el-checkbox-c25236a6.cjs → el-checkbox-b982e2ef.cjs} +1 -1
- package/es/{el-dialog-41ab8417.js → el-dialog-6a80e3d8.js} +4 -4
- package/es/{el-dialog-ae86edb8.cjs → el-dialog-ad7309e9.cjs} +1 -1
- package/es/{el-form-item-c3fe189b.cjs → el-form-item-4076e55f.cjs} +1 -1
- package/es/{el-form-item-c53c374d.js → el-form-item-4eca95be.js} +5 -5
- package/es/{el-input-7fd293af.cjs → el-input-172c49f8.cjs} +1 -1
- package/es/{el-input-2f75c4ba.js → el-input-cae60510.js} +49 -49
- package/es/{el-input-number-5193fe6d.js → el-input-number-c2499410.js} +4 -4
- package/es/{el-input-number-22e21d16.cjs → el-input-number-c2e71528.cjs} +1 -1
- package/es/{el-loading-cfd86c15.cjs → el-loading-05826e64.cjs} +1 -1
- package/es/{el-loading-f6022062.js → el-loading-c738468d.js} +1 -1
- package/es/{el-menu-item-17dc717e.cjs → el-menu-item-7f986598.cjs} +1 -1
- package/es/{el-menu-item-7e881203.js → el-menu-item-f904f685.js} +4 -4
- package/es/{el-message-e544a8f5.js → el-message-0df23ae7.js} +5 -5
- package/es/{el-message-5e6a6be9.cjs → el-message-a86c0efa.cjs} +1 -1
- package/es/{el-message-box-a93d2f6a.js → el-message-box-05d8cf39.js} +9 -9
- package/es/{el-message-box-c10adb52.cjs → el-message-box-40ff2af5.cjs} +1 -1
- package/es/{el-overlay-09ad71cd.js → el-overlay-cc9bc792.js} +18 -18
- package/es/{el-overlay-9e34965f.cjs → el-overlay-d7a6e4a9.cjs} +1 -1
- package/es/{el-popconfirm-70a976bf.cjs → el-popconfirm-737a015b.cjs} +1 -1
- package/es/{el-popconfirm-81dcd202.js → el-popconfirm-a6f66a0e.js} +4 -4
- package/es/{el-popper-b6c99b28.cjs → el-popper-7ba87e05.cjs} +1 -1
- package/es/{el-popper-b4f97157.js → el-popper-a38874f4.js} +1 -1
- package/es/{el-segmented-f8fce9ac.cjs → el-segmented-3fd66a0e.cjs} +1 -1
- package/es/{el-segmented-b868d074.js → el-segmented-51b1c797.js} +2 -2
- package/es/{el-select-d8d91db1.cjs → el-select-12f6deb7.cjs} +1 -1
- package/es/{el-select-95627997.js → el-select-1b149fab.js} +8 -8
- package/es/{el-table-column-376cd907.js → el-table-column-3e30ebae.js} +9 -9
- package/es/{el-table-column-c974cb96.cjs → el-table-column-516a0ed9.cjs} +1 -1
- package/es/{el-tag-66cab138.js → el-tag-0a25efdf.js} +2 -2
- package/es/{el-tag-a33c4b22.cjs → el-tag-789f05d3.cjs} +1 -1
- package/es/{el-text-c20a9f48.cjs → el-text-1470de46.cjs} +1 -1
- package/es/{el-text-ac60d0f2.js → el-text-73d899ff.js} +1 -1
- package/es/{index-d725fef6.cjs → index-2375023e.cjs} +138 -137
- package/es/{index-f967d6c1.cjs → index-269b22da.cjs} +1 -1
- package/es/{index-1f7d4f70.js → index-4194c942.js} +1 -1
- package/es/{index-e5566b94.js → index-42e59bf5.js} +1 -1
- package/es/{index-c108567d.cjs → index-4f48940d.cjs} +1 -1
- package/es/{index-d91dc23f.js → index-54d289d1.js} +2 -2
- package/es/{index-844bdd85.js → index-6806997d.js} +2 -2
- package/es/{index-f3562b52.cjs → index-696b6a94.cjs} +1 -1
- package/es/{index-88546436.js → index-6e967429.js} +2 -2
- package/es/{index-a871c3eb.js → index-87b4bf61.js} +75 -60
- package/es/{index-298075cf.cjs → index-8de94a49.cjs} +1 -1
- package/es/{index-57672682.js → index-94e43e0d.js} +2 -2
- package/es/{index-bc8e277e.js → index-ac98a4d8.js} +12827 -12573
- package/es/{index-11547a0c.cjs → index-c04f444f.cjs} +1 -1
- package/es/{index-098c2447.cjs → index-cebc7160.cjs} +1 -1
- package/es/{index-9b9ef5dd.cjs → index-ee977f79.cjs} +1 -1
- package/es/{python-ecde9ff2.js → python-a914569a.js} +39 -11
- package/es/{python-c27ba105.cjs → python-c67c8901.cjs} +2 -2
- package/es/style.css +1 -1
- package/es/{use-form-common-props-fd9b61a0.cjs → use-form-common-props-344056f9.cjs} +1 -1
- package/es/{use-form-common-props-815d48a6.js → use-form-common-props-47e50c10.js} +28 -28
- package/es/{use-global-config-30d7d8ce.cjs → use-global-config-cf78ebac.cjs} +1 -1
- package/es/{use-global-config-b5e9d3d5.js → use-global-config-f52caea0.js} +4 -4
- package/es/{validator-1b8a6128.cjs → validator-3cad04b2.cjs} +1 -1
- package/es/{validator-764a9db0.js → validator-94c04152.js} +1 -1
- package/es/{zh-cn-e963c628.js → zh-cn-4921961d.js} +1 -1
- package/es/{zh-cn-90317f62.cjs → zh-cn-aabfaa94.cjs} +1 -1
- package/lib/bundle.js +1 -1
- package/lib/bundle.umd.cjs +225 -223
- package/lib/{index-d976d634.js → index-0c373441.js} +29980 -29522
- package/lib/{python-12eba14f.js → python-4e746381.js} +1 -1
- package/lib/style.css +1 -1
- package/package.json +2 -1
- package/packages/MonacoEditor/index.vue +741 -70
- package/packages/VarietySearch/components/AddTag/index.vue +18 -6
- package/packages/VarietySearch/components/FactorScreen/index.vue +80 -12
- package/packages/VarietySearch/components/FactorScreen/tools.js +41 -0
- package/packages/VarietySearch/index.vue +0 -8
- package/src/main.ts +16 -11
- package/src/pages/MonacoEditor/index.vue +1 -0
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { debounce } from "st-func";
|
|
3
|
+
import { InfoFilled } from "@element-plus/icons-vue";
|
|
3
4
|
import { ref, onMounted, onUnmounted, nextTick, inject } from "vue";
|
|
5
|
+
import { extractVariables } from "./tools";
|
|
4
6
|
import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
|
|
5
7
|
import "monaco-editor/esm/vs/basic-languages/python/python.contribution";
|
|
6
8
|
import "monaco-editor/esm/vs/basic-languages/lua/lua.contribution";
|
|
7
|
-
import
|
|
9
|
+
import VarietySelect from "../VarSelectDialog/VarietySelect.vue";
|
|
8
10
|
|
|
9
11
|
const { request } = inject("stConfig"); // 组件库全局配置
|
|
10
12
|
|
|
11
13
|
const emit = defineEmits(["change"]);
|
|
12
14
|
const props = defineProps({
|
|
15
|
+
// 编辑器相关参数
|
|
13
16
|
defaultValue: {
|
|
14
17
|
type: String,
|
|
15
18
|
default: "",
|
|
@@ -27,6 +30,16 @@ const props = defineProps({
|
|
|
27
30
|
type: Boolean,
|
|
28
31
|
default: false,
|
|
29
32
|
},
|
|
33
|
+
// 变量列表开关
|
|
34
|
+
variableEnable: {
|
|
35
|
+
type: Boolean,
|
|
36
|
+
default: false,
|
|
37
|
+
},
|
|
38
|
+
// 变量列表类型
|
|
39
|
+
useCase: {
|
|
40
|
+
type: String,
|
|
41
|
+
default: "1", // 1-选股, 2-回测
|
|
42
|
+
},
|
|
30
43
|
});
|
|
31
44
|
|
|
32
45
|
let editorInstance = null;
|
|
@@ -39,6 +52,209 @@ const suggestionIndex = ref(-1);
|
|
|
39
52
|
const suggestionBoxRef = ref(null);
|
|
40
53
|
const isShowingSuggestions = ref(false);
|
|
41
54
|
|
|
55
|
+
// 变量列表相关参数
|
|
56
|
+
const variables = ref([]);
|
|
57
|
+
const variableIndex = ref(-1);
|
|
58
|
+
const variableBoxRef = ref(null);
|
|
59
|
+
const isShowingVariables = ref(false);
|
|
60
|
+
const currentVarName = ref(null);
|
|
61
|
+
const currentFormatList = ref([]);
|
|
62
|
+
const currentKeyword = ref("");
|
|
63
|
+
|
|
64
|
+
// 变量数据源
|
|
65
|
+
const varList = ref([]);
|
|
66
|
+
|
|
67
|
+
// 格式化配置项的下拉框数据源
|
|
68
|
+
const handleOptionsStrToArray = (str) => {
|
|
69
|
+
const trimmedStr = str.replace(/^\[|\]$/g, "");
|
|
70
|
+
const items = trimmedStr.split("],[");
|
|
71
|
+
|
|
72
|
+
return items.map((item) => {
|
|
73
|
+
const cleanItem = item.replace(/\[|\]/g, "");
|
|
74
|
+
const [label, value] = cleanItem.split(",");
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
label: label.trim(),
|
|
78
|
+
value: value.trim(),
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// 获取变量列表数据
|
|
84
|
+
const fetchVariables = async () => {
|
|
85
|
+
if (!props.variableEnable) return;
|
|
86
|
+
try {
|
|
87
|
+
const { body } = await request.post("/common/conf/queryAllBackVariables", { useCase: props.useCase });
|
|
88
|
+
varList.value = body ?? [];
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error("获取变量列表失败:", error);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// [变量列表] 数据筛选
|
|
95
|
+
const getVariables = debounce(async (keyword = "") => {
|
|
96
|
+
if (!props.variableEnable) return;
|
|
97
|
+
|
|
98
|
+
currentKeyword.value = keyword;
|
|
99
|
+
|
|
100
|
+
// 根据关键字筛选变量名
|
|
101
|
+
const filtered = varList.value.filter(({ varName }) => varName.toLowerCase().includes(keyword.toLowerCase()));
|
|
102
|
+
|
|
103
|
+
if (filtered.length > 0) {
|
|
104
|
+
showVariables(filtered);
|
|
105
|
+
} else {
|
|
106
|
+
hideVariables();
|
|
107
|
+
}
|
|
108
|
+
}, 200);
|
|
109
|
+
|
|
110
|
+
// [变量列表] 展示
|
|
111
|
+
const showVariables = async (options) => {
|
|
112
|
+
if (!props.variableEnable) return;
|
|
113
|
+
variables.value = options;
|
|
114
|
+
variableIndex.value = options.length > 0 ? 0 : -1;
|
|
115
|
+
isShowingVariables.value = true;
|
|
116
|
+
|
|
117
|
+
// 如果有选中项,更新其格式列表
|
|
118
|
+
if (variableIndex.value !== -1) {
|
|
119
|
+
updateCurrentFormatList();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
updateVariableBoxPosition();
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// [变量列表] 隐藏
|
|
126
|
+
const hideVariables = () => {
|
|
127
|
+
if (!props.variableEnable) return;
|
|
128
|
+
variables.value = [];
|
|
129
|
+
variableIndex.value = -1;
|
|
130
|
+
isShowingVariables.value = false;
|
|
131
|
+
currentVarName.value = null;
|
|
132
|
+
currentFormatList.value = [];
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// [变量列表] 更新当前选中变量的格式列表
|
|
136
|
+
const updateCurrentFormatList = () => {
|
|
137
|
+
if (variableIndex.value === -1 || !variables.value[variableIndex.value]) return;
|
|
138
|
+
|
|
139
|
+
const selectedVar = variables.value[variableIndex.value];
|
|
140
|
+
currentVarName.value = selectedVar.varName;
|
|
141
|
+
currentFormatList.value = selectedVar.formatList ?? [];
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// [变量列表] 更新DOM位置
|
|
145
|
+
const updateVariableBoxPosition = () => {
|
|
146
|
+
if (!props.variableEnable) return;
|
|
147
|
+
nextTick(() => {
|
|
148
|
+
if (!editorInstance || !variableBoxRef.value) return;
|
|
149
|
+
const position = editorInstance.getPosition();
|
|
150
|
+
const cursorCoords = editorInstance.getScrolledVisiblePosition(position);
|
|
151
|
+
|
|
152
|
+
if (cursorCoords) {
|
|
153
|
+
const editorDom = editorInstance.getDomNode();
|
|
154
|
+
const editorRect = editorDom.getBoundingClientRect();
|
|
155
|
+
|
|
156
|
+
// 计算相对于编辑器容器的位置(在光标右侧,但比建议列表低一些)
|
|
157
|
+
const left = cursorCoords.left + editorRect.left + 40;
|
|
158
|
+
const top = cursorCoords.top + editorRect.top + cursorCoords.height + 5;
|
|
159
|
+
|
|
160
|
+
variableBoxRef.value.style.left = `${left}px`;
|
|
161
|
+
variableBoxRef.value.style.top = `${top}px`;
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// [变量列表] 插入变量内容
|
|
167
|
+
const insertVariableContent = (configList) => {
|
|
168
|
+
if (!editorInstance) return;
|
|
169
|
+
|
|
170
|
+
// 1.校验是否填写完整 + 生成输出值
|
|
171
|
+
const result = [];
|
|
172
|
+
for (let index = 0; index < configList.length; index++) {
|
|
173
|
+
const item = configList[index];
|
|
174
|
+
switch (item.vtype) {
|
|
175
|
+
case "text": {
|
|
176
|
+
result.push(item.param);
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
default: {
|
|
180
|
+
if (!item.modelValue) {
|
|
181
|
+
ElMessage.error("请检查插入格式内是否填写完整");
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
let formatValue = item.modelValue;
|
|
185
|
+
if (item.prefix) formatValue = `${item.prefix}${formatValue}`;
|
|
186
|
+
if (item.suffix) formatValue = `${formatValue}${item.suffix}`;
|
|
187
|
+
result.push(formatValue);
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// 2.插入内容
|
|
194
|
+
const content = result.join("_");
|
|
195
|
+
const position = editorInstance.getPosition();
|
|
196
|
+
|
|
197
|
+
const currentValue = editorInstance.getValue();
|
|
198
|
+
const lines = currentValue.split("\n");
|
|
199
|
+
|
|
200
|
+
// 如果光标位置有效
|
|
201
|
+
if (position.lineNumber <= lines.length) {
|
|
202
|
+
const lineIndex = position.lineNumber - 1;
|
|
203
|
+
const line = lines[lineIndex];
|
|
204
|
+
const columnIndex = position.column - 1;
|
|
205
|
+
|
|
206
|
+
// 获取光标前后的字符
|
|
207
|
+
const prevChar = columnIndex > 0 ? line[columnIndex - 1] : "";
|
|
208
|
+
const nextChar = columnIndex < line.length ? line[columnIndex] : "";
|
|
209
|
+
|
|
210
|
+
// 检测是否需要添加空格
|
|
211
|
+
let contentToInsert = content;
|
|
212
|
+
|
|
213
|
+
// 如果前面有内容且不是空格或行首,在前面添加空格
|
|
214
|
+
if (prevChar && prevChar !== " " && !/[\s({[ ]/.test(prevChar)) {
|
|
215
|
+
contentToInsert = " " + contentToInsert;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// 如果后面有内容且不是空格或行尾,在后面添加空格
|
|
219
|
+
if (nextChar && nextChar !== " " && !/[\s)}\]]/.test(nextChar)) {
|
|
220
|
+
contentToInsert = contentToInsert + " ";
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// 获取当前光标前的单词范围(用于替换)
|
|
224
|
+
const wordUntilPosition = editorInstance.getModel().getWordUntilPosition(position);
|
|
225
|
+
|
|
226
|
+
// 如果当前有正在输入的变量名,替换整个单词
|
|
227
|
+
const startPosition = {
|
|
228
|
+
lineNumber: position.lineNumber,
|
|
229
|
+
column: wordUntilPosition.startColumn,
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const endPosition = {
|
|
233
|
+
lineNumber: position.lineNumber,
|
|
234
|
+
column: position.column,
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// 执行编辑操作
|
|
238
|
+
editorInstance.executeEdits("variable-insert", [
|
|
239
|
+
{
|
|
240
|
+
range: new monaco.Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column),
|
|
241
|
+
text: contentToInsert,
|
|
242
|
+
forceMoveMarkers: true,
|
|
243
|
+
},
|
|
244
|
+
]);
|
|
245
|
+
|
|
246
|
+
// 将光标移动到插入内容之后
|
|
247
|
+
const newColumn = startPosition.column + contentToInsert.length;
|
|
248
|
+
editorInstance.setPosition({
|
|
249
|
+
lineNumber: position.lineNumber,
|
|
250
|
+
column: newColumn,
|
|
251
|
+
});
|
|
252
|
+
editorInstance.focus();
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// 插入后保持变量列表显示(不关闭)
|
|
256
|
+
};
|
|
257
|
+
|
|
42
258
|
// [建议列表] 数据获取
|
|
43
259
|
const getSuggestions = debounce(async (keyword = "") => {
|
|
44
260
|
if (!props.suggestionEnable) return;
|
|
@@ -55,6 +271,7 @@ const getSuggestions = debounce(async (keyword = "") => {
|
|
|
55
271
|
hideSuggestions();
|
|
56
272
|
}
|
|
57
273
|
}, 200);
|
|
274
|
+
|
|
58
275
|
// [建议列表] 展示
|
|
59
276
|
const showSuggestions = async (options) => {
|
|
60
277
|
if (!props.suggestionEnable) return;
|
|
@@ -63,6 +280,7 @@ const showSuggestions = async (options) => {
|
|
|
63
280
|
isShowingSuggestions.value = true;
|
|
64
281
|
updateSuggestionBoxPosition();
|
|
65
282
|
};
|
|
283
|
+
|
|
66
284
|
// [建议列表] 隐藏
|
|
67
285
|
const hideSuggestions = () => {
|
|
68
286
|
if (!props.suggestionEnable) return;
|
|
@@ -70,6 +288,7 @@ const hideSuggestions = () => {
|
|
|
70
288
|
suggestionIndex.value = -1;
|
|
71
289
|
isShowingSuggestions.value = false;
|
|
72
290
|
};
|
|
291
|
+
|
|
73
292
|
// [建议列表] 更新DOM位置
|
|
74
293
|
const updateSuggestionBoxPosition = () => {
|
|
75
294
|
if (!props.suggestionEnable) return;
|
|
@@ -82,8 +301,7 @@ const updateSuggestionBoxPosition = () => {
|
|
|
82
301
|
const editorDom = editorInstance.getDomNode();
|
|
83
302
|
const editorRect = editorDom.getBoundingClientRect();
|
|
84
303
|
|
|
85
|
-
|
|
86
|
-
const left = cursorCoords.left + editorRect.left + 40; // 在光标右侧
|
|
304
|
+
const left = cursorCoords.left + editorRect.left + 40;
|
|
87
305
|
const top = cursorCoords.top + editorRect.top + cursorCoords.height;
|
|
88
306
|
|
|
89
307
|
suggestionBoxRef.value.style.left = `${left}px`;
|
|
@@ -91,6 +309,7 @@ const updateSuggestionBoxPosition = () => {
|
|
|
91
309
|
}
|
|
92
310
|
});
|
|
93
311
|
};
|
|
312
|
+
|
|
94
313
|
// [建议列表] 插入内容到编辑器
|
|
95
314
|
const insertSelectedSuggestion = () => {
|
|
96
315
|
if (!props.suggestionEnable) return;
|
|
@@ -102,7 +321,6 @@ const insertSelectedSuggestion = () => {
|
|
|
102
321
|
if (varArray.length) {
|
|
103
322
|
const str = varArray.reduce((result, item, index, arry) => {
|
|
104
323
|
result += `${item}=`;
|
|
105
|
-
// 如果不是最后一个, 就需要加个逗号
|
|
106
324
|
if (index < arry.length - 1) result += ",";
|
|
107
325
|
return result;
|
|
108
326
|
}, "");
|
|
@@ -148,9 +366,49 @@ const insertSelectedSuggestion = () => {
|
|
|
148
366
|
|
|
149
367
|
hideSuggestions();
|
|
150
368
|
};
|
|
151
|
-
|
|
152
|
-
|
|
369
|
+
|
|
370
|
+
// [建议列表] 选项自动滚动
|
|
371
|
+
const scrollToSelectedSuggestion = () => {
|
|
153
372
|
if (!props.suggestionEnable) return;
|
|
373
|
+
if (!suggestionBoxRef.value || suggestionIndex.value === -1) return;
|
|
374
|
+
|
|
375
|
+
const suggestionList = suggestionBoxRef.value.querySelector(".suggestion-list");
|
|
376
|
+
const selectedItem = suggestionBoxRef.value.querySelector(".suggestion-item.selected");
|
|
377
|
+
|
|
378
|
+
if (suggestionList && selectedItem) {
|
|
379
|
+
const listRect = suggestionList.getBoundingClientRect();
|
|
380
|
+
const itemRect = selectedItem.getBoundingClientRect();
|
|
381
|
+
|
|
382
|
+
if (itemRect.top < listRect.top) {
|
|
383
|
+
suggestionList.scrollTop -= listRect.top - itemRect.top;
|
|
384
|
+
} else if (itemRect.bottom > listRect.bottom) {
|
|
385
|
+
suggestionList.scrollTop += itemRect.bottom - listRect.bottom;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
// [变量列表] 选项自动滚动
|
|
391
|
+
const scrollToSelectedVariable = () => {
|
|
392
|
+
if (!props.variableEnable) return;
|
|
393
|
+
if (!variableBoxRef.value || variableIndex.value === -1) return;
|
|
394
|
+
|
|
395
|
+
const variableList = variableBoxRef.value.querySelector(".variable-list");
|
|
396
|
+
const selectedItem = variableBoxRef.value.querySelector(".variable-item.selected");
|
|
397
|
+
|
|
398
|
+
if (variableList && selectedItem) {
|
|
399
|
+
const listRect = variableList.getBoundingClientRect();
|
|
400
|
+
const itemRect = selectedItem.getBoundingClientRect();
|
|
401
|
+
|
|
402
|
+
if (itemRect.top < listRect.top) {
|
|
403
|
+
variableList.scrollTop -= listRect.top - itemRect.top;
|
|
404
|
+
} else if (itemRect.bottom > listRect.bottom) {
|
|
405
|
+
variableList.scrollTop += itemRect.bottom - listRect.bottom;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
// 检查当前输入内容,决定显示建议列表还是变量列表
|
|
411
|
+
const checkForCompletions = async () => {
|
|
154
412
|
const position = editorInstance.getPosition();
|
|
155
413
|
const model = editorInstance.getModel();
|
|
156
414
|
const lineContent = model.getLineContent(position.lineNumber);
|
|
@@ -158,104 +416,140 @@ const checkForSuggestions = async () => {
|
|
|
158
416
|
const textBeforeCursor = lineContent.substring(0, position.column - 1);
|
|
159
417
|
const lastHashIndex = textBeforeCursor.lastIndexOf("#");
|
|
160
418
|
|
|
419
|
+
// 如果是#触发,显示建议列表
|
|
161
420
|
if (lastHashIndex !== -1) {
|
|
421
|
+
// 如果变量列表正在显示,先隐藏
|
|
422
|
+
if (isShowingVariables.value) hideVariables();
|
|
423
|
+
|
|
162
424
|
const keyword = textBeforeCursor.substring(lastHashIndex + 1);
|
|
163
425
|
if (lastCursorPosition && (lastCursorPosition.lineNumber !== position.lineNumber || lastCursorPosition.column !== position.column)) {
|
|
164
426
|
hideSuggestions();
|
|
165
427
|
}
|
|
166
428
|
lastCursorPosition = { ...position };
|
|
167
429
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
430
|
+
if (props.suggestionEnable) {
|
|
431
|
+
getSuggestions(keyword);
|
|
432
|
+
}
|
|
171
433
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (!suggestionBoxRef.value || suggestionIndex.value === -1) return;
|
|
434
|
+
// 否则检查变量列表
|
|
435
|
+
else {
|
|
436
|
+
// 如果建议列表正在显示,先隐藏
|
|
437
|
+
if (isShowingSuggestions.value) hideSuggestions();
|
|
177
438
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (suggestionList && selectedItem) {
|
|
182
|
-
const listRect = suggestionList.getBoundingClientRect();
|
|
183
|
-
const itemRect = selectedItem.getBoundingClientRect();
|
|
439
|
+
// 获取光标前的单词作为关键字
|
|
440
|
+
const wordUntilPosition = model.getWordUntilPosition(position);
|
|
441
|
+
const keyword = wordUntilPosition.word;
|
|
184
442
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
suggestionList.scrollTop -= listRect.top - itemRect.top;
|
|
443
|
+
if (lastCursorPosition && (lastCursorPosition.lineNumber !== position.lineNumber || lastCursorPosition.column !== position.column)) {
|
|
444
|
+
hideVariables();
|
|
188
445
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
446
|
+
lastCursorPosition = { ...position };
|
|
447
|
+
|
|
448
|
+
if (props.variableEnable && keyword.length > 0) {
|
|
449
|
+
getVariables(keyword);
|
|
450
|
+
} else if (keyword.length === 0) {
|
|
451
|
+
hideVariables();
|
|
192
452
|
}
|
|
193
453
|
}
|
|
194
454
|
};
|
|
195
455
|
|
|
196
456
|
// [代码编辑器] 键盘事件
|
|
197
457
|
const handleKeyDown = (e) => {
|
|
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
|
-
e.preventDefault();
|
|
226
|
-
e.stopPropagation();
|
|
227
|
-
insertSelectedSuggestion();
|
|
228
|
-
break;
|
|
458
|
+
// 变量列表键盘导航
|
|
459
|
+
if (isShowingVariables.value) {
|
|
460
|
+
switch (e.code) {
|
|
461
|
+
case "ArrowUp": {
|
|
462
|
+
e.preventDefault();
|
|
463
|
+
e.stopPropagation();
|
|
464
|
+
variableIndex.value = variableIndex.value <= 0 ? variables.value.length - 1 : variableIndex.value - 1;
|
|
465
|
+
updateCurrentFormatList();
|
|
466
|
+
nextTick(() => scrollToSelectedVariable());
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
case "ArrowDown": {
|
|
470
|
+
e.preventDefault();
|
|
471
|
+
e.stopPropagation();
|
|
472
|
+
variableIndex.value = variableIndex.value >= variables.value.length - 1 ? 0 : variableIndex.value + 1;
|
|
473
|
+
updateCurrentFormatList();
|
|
474
|
+
nextTick(() => scrollToSelectedVariable());
|
|
475
|
+
break;
|
|
476
|
+
}
|
|
477
|
+
case "Escape": {
|
|
478
|
+
e.preventDefault();
|
|
479
|
+
e.stopPropagation();
|
|
480
|
+
hideVariables();
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
default:
|
|
484
|
+
break;
|
|
229
485
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// 建议列表键盘导航
|
|
489
|
+
if (isShowingSuggestions.value) {
|
|
490
|
+
switch (e.code) {
|
|
491
|
+
case "ArrowUp": {
|
|
492
|
+
e.preventDefault();
|
|
493
|
+
e.stopPropagation();
|
|
494
|
+
suggestionIndex.value = suggestionIndex.value <= 0 ? suggestions.value.length - 1 : suggestionIndex.value - 1;
|
|
495
|
+
nextTick(() => scrollToSelectedSuggestion());
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
case "ArrowDown": {
|
|
499
|
+
e.preventDefault();
|
|
500
|
+
e.stopPropagation();
|
|
501
|
+
suggestionIndex.value = suggestionIndex.value >= suggestions.value.length - 1 ? 0 : suggestionIndex.value + 1;
|
|
502
|
+
nextTick(() => scrollToSelectedSuggestion());
|
|
503
|
+
break;
|
|
504
|
+
}
|
|
505
|
+
case "Enter": {
|
|
506
|
+
if (isShowingSuggestions.value) {
|
|
507
|
+
e.preventDefault();
|
|
508
|
+
e.stopPropagation();
|
|
509
|
+
insertSelectedSuggestion();
|
|
510
|
+
}
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
case "Escape": {
|
|
514
|
+
e.preventDefault();
|
|
515
|
+
e.stopPropagation();
|
|
516
|
+
if (isShowingSuggestions.value) hideSuggestions();
|
|
517
|
+
if (isShowingVariables.value) hideVariables();
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
520
|
+
default:
|
|
521
|
+
break;
|
|
235
522
|
}
|
|
236
|
-
default:
|
|
237
|
-
break;
|
|
238
523
|
}
|
|
239
524
|
};
|
|
525
|
+
|
|
240
526
|
// [代码编辑器] 内容变化回调
|
|
241
527
|
const handleContentChange = (event) => {
|
|
242
528
|
if (!editorInstance) return;
|
|
243
529
|
emit("change", editorInstance.getValue());
|
|
244
|
-
|
|
530
|
+
checkForCompletions();
|
|
245
531
|
};
|
|
532
|
+
|
|
246
533
|
// [代码编辑器] 光标变化回调
|
|
247
534
|
const handleCursorPositionChange = (event) => {
|
|
248
535
|
if (isShowingSuggestions.value) {
|
|
249
536
|
updateSuggestionBoxPosition();
|
|
250
537
|
}
|
|
538
|
+
if (isShowingVariables.value) {
|
|
539
|
+
updateVariableBoxPosition();
|
|
540
|
+
}
|
|
251
541
|
};
|
|
252
542
|
|
|
253
543
|
// [document] 全局监听的点击事件
|
|
254
544
|
const handleClickOutside = (event) => {
|
|
255
|
-
//
|
|
545
|
+
// 如果点击了建议列表外面的区域,就自动关闭
|
|
256
546
|
if (suggestionBoxRef.value && !suggestionBoxRef.value.contains(event.target)) {
|
|
257
547
|
hideSuggestions();
|
|
258
548
|
}
|
|
549
|
+
// 如果点击了变量列表外面的区域,就自动关闭
|
|
550
|
+
if (variableBoxRef.value && !variableBoxRef.value.contains(event.target)) {
|
|
551
|
+
hideVariables();
|
|
552
|
+
}
|
|
259
553
|
};
|
|
260
554
|
|
|
261
555
|
onMounted(() => {
|
|
@@ -264,15 +558,22 @@ onMounted(() => {
|
|
|
264
558
|
language: props.language,
|
|
265
559
|
theme: props.theme,
|
|
266
560
|
});
|
|
561
|
+
|
|
267
562
|
editorInstance.onKeyDown(handleKeyDown);
|
|
268
563
|
editorInstance.onDidChangeModelContent(handleContentChange);
|
|
269
564
|
editorInstance.onDidChangeCursorPosition(handleCursorPositionChange);
|
|
565
|
+
|
|
270
566
|
document.addEventListener("click", handleClickOutside);
|
|
567
|
+
|
|
568
|
+
// 获取变量列表数据
|
|
569
|
+
fetchVariables();
|
|
271
570
|
});
|
|
571
|
+
|
|
272
572
|
onUnmounted(() => {
|
|
273
573
|
editorInstance?.dispose();
|
|
274
574
|
document.removeEventListener("click", handleClickOutside);
|
|
275
575
|
});
|
|
576
|
+
|
|
276
577
|
defineExpose({
|
|
277
578
|
resize: () => {
|
|
278
579
|
editorInstance.layout();
|
|
@@ -295,11 +596,9 @@ defineExpose({
|
|
|
295
596
|
const model = editorInstance.getModel();
|
|
296
597
|
if (!model) return;
|
|
297
598
|
|
|
298
|
-
// 获取最后一行
|
|
299
599
|
const lineCount = model.getLineCount();
|
|
300
600
|
const lastLine = model.getLineContent(lineCount);
|
|
301
601
|
|
|
302
|
-
// 设置光标位置到最后一行末尾
|
|
303
602
|
const position = {
|
|
304
603
|
lineNumber: lineCount,
|
|
305
604
|
column: lastLine.length + 1,
|
|
@@ -307,8 +606,6 @@ defineExpose({
|
|
|
307
606
|
|
|
308
607
|
editorInstance.setPosition(position);
|
|
309
608
|
editorInstance.focus();
|
|
310
|
-
|
|
311
|
-
// 滚动到光标位置
|
|
312
609
|
editorInstance.revealPositionInCenter(position);
|
|
313
610
|
},
|
|
314
611
|
});
|
|
@@ -321,6 +618,7 @@ defineExpose({
|
|
|
321
618
|
ref="editorContainer"
|
|
322
619
|
class="editor-container"
|
|
323
620
|
/>
|
|
621
|
+
|
|
324
622
|
<!-- 建议列表 -->
|
|
325
623
|
<Teleport
|
|
326
624
|
to="body"
|
|
@@ -350,9 +648,157 @@ defineExpose({
|
|
|
350
648
|
<div class="suggestion-footer">使用 ↑↓ 选择,Enter 确认,Esc 取消</div>
|
|
351
649
|
</div>
|
|
352
650
|
</Teleport>
|
|
651
|
+
|
|
652
|
+
<!-- 变量列表 -->
|
|
653
|
+
<Teleport
|
|
654
|
+
to="body"
|
|
655
|
+
v-if="isShowingVariables && variables.length > 0"
|
|
656
|
+
>
|
|
657
|
+
<div
|
|
658
|
+
ref="variableBoxRef"
|
|
659
|
+
class="variable-box"
|
|
660
|
+
>
|
|
661
|
+
<div class="variable-header">
|
|
662
|
+
<span class="variable-title">变量列表</span>
|
|
663
|
+
<span class="variable-count">{{ variables.length }} 项</span>
|
|
664
|
+
<span
|
|
665
|
+
class="variable-keyword"
|
|
666
|
+
v-if="currentKeyword"
|
|
667
|
+
>"{{ currentKeyword }}"</span
|
|
668
|
+
>
|
|
669
|
+
</div>
|
|
670
|
+
|
|
671
|
+
<div class="variable-content">
|
|
672
|
+
<!-- 左侧变量名列表 -->
|
|
673
|
+
<div class="variable-list">
|
|
674
|
+
<div
|
|
675
|
+
v-for="(item, index) in variables"
|
|
676
|
+
:key="item.varName"
|
|
677
|
+
:class="['variable-item', { selected: index === variableIndex }]"
|
|
678
|
+
@click="
|
|
679
|
+
variableIndex = index;
|
|
680
|
+
updateCurrentFormatList();
|
|
681
|
+
"
|
|
682
|
+
>
|
|
683
|
+
<span class="variable-name">{{ item.varName }}</span>
|
|
684
|
+
</div>
|
|
685
|
+
</div>
|
|
686
|
+
|
|
687
|
+
<!-- 右侧格式配置区域 -->
|
|
688
|
+
<div
|
|
689
|
+
class="format-section"
|
|
690
|
+
v-if="currentFormatList.length"
|
|
691
|
+
>
|
|
692
|
+
<div
|
|
693
|
+
class="format-item"
|
|
694
|
+
v-for="(formatItem, formatIndex) in currentFormatList"
|
|
695
|
+
:key="formatIndex"
|
|
696
|
+
>
|
|
697
|
+
<div class="format-header">
|
|
698
|
+
<span>格式{{ formatIndex + 1 }}</span>
|
|
699
|
+
<el-tooltip
|
|
700
|
+
effect="dark"
|
|
701
|
+
placement="top-start"
|
|
702
|
+
>
|
|
703
|
+
<template #content>
|
|
704
|
+
<div style="max-width: 820px">
|
|
705
|
+
<span style="white-space: pre-line">{{ formatItem.tip }}</span>
|
|
706
|
+
</div>
|
|
707
|
+
</template>
|
|
708
|
+
<el-icon><InfoFilled /></el-icon>
|
|
709
|
+
</el-tooltip>
|
|
710
|
+
</div>
|
|
711
|
+
|
|
712
|
+
<!-- 配置项 -->
|
|
713
|
+
<div class="config-list">
|
|
714
|
+
<template v-for="(config, configIndex) in formatItem.configList">
|
|
715
|
+
<div class="config-item">
|
|
716
|
+
<!-- 类型: 固定值 -->
|
|
717
|
+
<template v-if="config.vtype === 'text'">
|
|
718
|
+
<span>{{ config.param }}</span>
|
|
719
|
+
</template>
|
|
720
|
+
<template v-if="config.vtype === 'inputVariety'">
|
|
721
|
+
<VarietySelect
|
|
722
|
+
size="small"
|
|
723
|
+
:placeholder="config.param"
|
|
724
|
+
:selectClearEnable="false"
|
|
725
|
+
:labelShowEnable="false"
|
|
726
|
+
@select="({ name, code }) => (config.modelValue = code)"
|
|
727
|
+
@change="(value) => (config.modelValue = value)"
|
|
728
|
+
style="width: 100px"
|
|
729
|
+
/>
|
|
730
|
+
</template>
|
|
731
|
+
<template v-if="config.vtype === 'input'">
|
|
732
|
+
<span v-if="config.prefix">{{ config.prefix }}</span>
|
|
733
|
+
<el-input
|
|
734
|
+
v-model="config.modelValue"
|
|
735
|
+
:placeholder="config.param"
|
|
736
|
+
size="small"
|
|
737
|
+
/>
|
|
738
|
+
<span v-if="config.suffix">{{ config.suffix }}</span>
|
|
739
|
+
</template>
|
|
740
|
+
<template v-if="config.vtype === 'select'">
|
|
741
|
+
<el-select
|
|
742
|
+
v-model="config.modelValue"
|
|
743
|
+
:placeholder="config.param"
|
|
744
|
+
clearable
|
|
745
|
+
size="small"
|
|
746
|
+
>
|
|
747
|
+
<el-option
|
|
748
|
+
v-for="item in handleOptionsStrToArray(config.optionsStr)"
|
|
749
|
+
:key="item.value"
|
|
750
|
+
:label="item.label"
|
|
751
|
+
:value="item.value"
|
|
752
|
+
/>
|
|
753
|
+
</el-select>
|
|
754
|
+
</template>
|
|
755
|
+
</div>
|
|
756
|
+
<span
|
|
757
|
+
v-if="configIndex !== formatItem.configList.length - 1"
|
|
758
|
+
class="separator"
|
|
759
|
+
>_</span
|
|
760
|
+
>
|
|
761
|
+
</template>
|
|
762
|
+
</div>
|
|
763
|
+
|
|
764
|
+
<!-- 插入变量按钮 -->
|
|
765
|
+
<el-button
|
|
766
|
+
type="primary"
|
|
767
|
+
size="small"
|
|
768
|
+
class="insert-btn"
|
|
769
|
+
@click="insertVariableContent(formatItem.configList)"
|
|
770
|
+
>
|
|
771
|
+
插入变量
|
|
772
|
+
</el-button>
|
|
773
|
+
</div>
|
|
774
|
+
</div>
|
|
775
|
+
</div>
|
|
776
|
+
|
|
777
|
+
<div class="variable-footer">使用 ↑↓ 选择变量,点击插入按钮确认,Esc 取消</div>
|
|
778
|
+
</div>
|
|
779
|
+
</Teleport>
|
|
353
780
|
</div>
|
|
354
781
|
</template>
|
|
355
782
|
|
|
783
|
+
<style lang="scss">
|
|
784
|
+
/* 变量列表下拉框和tooltip的全局样式 */
|
|
785
|
+
.variable-select-popper,
|
|
786
|
+
.variable-variety-popper,
|
|
787
|
+
.variable-tooltip-popper {
|
|
788
|
+
z-index: 100000 !important;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/* 确保所有 Element Plus 的弹层都有足够高的层级 */
|
|
792
|
+
.el-popper {
|
|
793
|
+
z-index: 100000 !important;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/* 如果是旧版本 Element Plus */
|
|
797
|
+
.el-select__popper,
|
|
798
|
+
.el-tooltip__popper {
|
|
799
|
+
z-index: 100000 !important;
|
|
800
|
+
}
|
|
801
|
+
</style>
|
|
356
802
|
<style scoped lang="scss">
|
|
357
803
|
.editor-wrapper {
|
|
358
804
|
position: relative;
|
|
@@ -363,6 +809,8 @@ defineExpose({
|
|
|
363
809
|
width: 100%;
|
|
364
810
|
height: 100%;
|
|
365
811
|
}
|
|
812
|
+
|
|
813
|
+
// 建议列表样式
|
|
366
814
|
.suggestion-box {
|
|
367
815
|
position: fixed;
|
|
368
816
|
background: #1e1e1e;
|
|
@@ -387,6 +835,7 @@ defineExpose({
|
|
|
387
835
|
transform: rotate(45deg);
|
|
388
836
|
z-index: -1;
|
|
389
837
|
}
|
|
838
|
+
|
|
390
839
|
.suggestion-header {
|
|
391
840
|
display: flex;
|
|
392
841
|
justify-content: space-between;
|
|
@@ -406,6 +855,7 @@ defineExpose({
|
|
|
406
855
|
opacity: 0.8;
|
|
407
856
|
}
|
|
408
857
|
}
|
|
858
|
+
|
|
409
859
|
.suggestion-list {
|
|
410
860
|
max-height: 200px;
|
|
411
861
|
overflow-y: auto;
|
|
@@ -458,6 +908,7 @@ defineExpose({
|
|
|
458
908
|
}
|
|
459
909
|
}
|
|
460
910
|
}
|
|
911
|
+
|
|
461
912
|
.suggestion-footer {
|
|
462
913
|
padding: 6px 12px;
|
|
463
914
|
background: #2d2d30;
|
|
@@ -467,4 +918,224 @@ defineExpose({
|
|
|
467
918
|
text-align: center;
|
|
468
919
|
}
|
|
469
920
|
}
|
|
921
|
+
// 变量列表样式
|
|
922
|
+
.variable-box {
|
|
923
|
+
position: fixed;
|
|
924
|
+
background: #1e1e1e;
|
|
925
|
+
border: 1px solid #444;
|
|
926
|
+
border-radius: 6px;
|
|
927
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.6);
|
|
928
|
+
z-index: 9999;
|
|
929
|
+
min-width: 600px;
|
|
930
|
+
max-width: 900px;
|
|
931
|
+
overflow: hidden;
|
|
932
|
+
|
|
933
|
+
&::before {
|
|
934
|
+
content: "";
|
|
935
|
+
position: absolute;
|
|
936
|
+
top: -6px;
|
|
937
|
+
left: 12px;
|
|
938
|
+
width: 12px;
|
|
939
|
+
height: 12px;
|
|
940
|
+
background: #1e1e1e;
|
|
941
|
+
border-left: 1px solid #444;
|
|
942
|
+
border-top: 1px solid #444;
|
|
943
|
+
transform: rotate(45deg);
|
|
944
|
+
z-index: -1;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
.variable-header {
|
|
948
|
+
display: flex;
|
|
949
|
+
justify-content: space-between;
|
|
950
|
+
align-items: center;
|
|
951
|
+
padding: 8px 12px;
|
|
952
|
+
background: #2d2d30;
|
|
953
|
+
border-bottom: 1px solid #444;
|
|
954
|
+
font-size: 12px;
|
|
955
|
+
color: #969696;
|
|
956
|
+
|
|
957
|
+
.variable-title {
|
|
958
|
+
font-weight: 600;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
.variable-count {
|
|
962
|
+
font-size: 11px;
|
|
963
|
+
opacity: 0.8;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
.variable-keyword {
|
|
967
|
+
font-size: 11px;
|
|
968
|
+
color: #007acc;
|
|
969
|
+
background: #09477133;
|
|
970
|
+
padding: 2px 6px;
|
|
971
|
+
border-radius: 4px;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
.variable-content {
|
|
976
|
+
display: flex;
|
|
977
|
+
max-height: 300px;
|
|
978
|
+
overflow: hidden;
|
|
979
|
+
|
|
980
|
+
.variable-list {
|
|
981
|
+
width: 160px;
|
|
982
|
+
border-right: 1px solid #444;
|
|
983
|
+
overflow-y: auto;
|
|
984
|
+
padding: 4px 0;
|
|
985
|
+
|
|
986
|
+
&::-webkit-scrollbar {
|
|
987
|
+
width: 6px;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
&::-webkit-scrollbar-track {
|
|
991
|
+
background: transparent;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
&::-webkit-scrollbar-thumb {
|
|
995
|
+
background: #424242;
|
|
996
|
+
border-radius: 3px;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
.variable-item {
|
|
1000
|
+
padding: 8px 12px;
|
|
1001
|
+
cursor: pointer;
|
|
1002
|
+
border-left: 3px solid transparent;
|
|
1003
|
+
font-size: 12px;
|
|
1004
|
+
color: #d4d4d4;
|
|
1005
|
+
|
|
1006
|
+
&:hover {
|
|
1007
|
+
background: #2a2d2e;
|
|
1008
|
+
border-left-color: #007acc;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
&.selected {
|
|
1012
|
+
background: #094771;
|
|
1013
|
+
border-left-color: #007acc;
|
|
1014
|
+
color: #ffffff;
|
|
1015
|
+
font-weight: 500;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
.format-section {
|
|
1021
|
+
flex: 1;
|
|
1022
|
+
padding: 12px;
|
|
1023
|
+
overflow-y: auto;
|
|
1024
|
+
max-height: 300px;
|
|
1025
|
+
|
|
1026
|
+
&::-webkit-scrollbar {
|
|
1027
|
+
width: 6px;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
&::-webkit-scrollbar-track {
|
|
1031
|
+
background: transparent;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
&::-webkit-scrollbar-thumb {
|
|
1035
|
+
background: #424242;
|
|
1036
|
+
border-radius: 3px;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
.format-item {
|
|
1040
|
+
margin-bottom: 16px;
|
|
1041
|
+
padding: 8px;
|
|
1042
|
+
background: #2d2d30;
|
|
1043
|
+
border-radius: 4px;
|
|
1044
|
+
|
|
1045
|
+
&:last-child {
|
|
1046
|
+
margin-bottom: 0;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
.format-header {
|
|
1050
|
+
display: flex;
|
|
1051
|
+
align-items: center;
|
|
1052
|
+
gap: 6px;
|
|
1053
|
+
margin-bottom: 8px;
|
|
1054
|
+
font-size: 11px;
|
|
1055
|
+
color: #969696;
|
|
1056
|
+
|
|
1057
|
+
.el-icon {
|
|
1058
|
+
cursor: help;
|
|
1059
|
+
font-size: 14px;
|
|
1060
|
+
|
|
1061
|
+
&:hover {
|
|
1062
|
+
color: #007acc;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
.config-list {
|
|
1068
|
+
display: flex;
|
|
1069
|
+
align-items: center;
|
|
1070
|
+
flex-wrap: wrap;
|
|
1071
|
+
gap: 4px 8px;
|
|
1072
|
+
margin-bottom: 8px;
|
|
1073
|
+
|
|
1074
|
+
.config-item {
|
|
1075
|
+
display: flex;
|
|
1076
|
+
align-items: center;
|
|
1077
|
+
gap: 2px;
|
|
1078
|
+
|
|
1079
|
+
span {
|
|
1080
|
+
font-size: 12px;
|
|
1081
|
+
color: #d4d4d4;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
:deep(.el-input) {
|
|
1085
|
+
width: 100px;
|
|
1086
|
+
|
|
1087
|
+
.el-input__wrapper {
|
|
1088
|
+
background: #3c3c3c;
|
|
1089
|
+
box-shadow: none;
|
|
1090
|
+
padding: 1px 8px;
|
|
1091
|
+
|
|
1092
|
+
input {
|
|
1093
|
+
color: #d4d4d4;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
:deep(.el-select) {
|
|
1099
|
+
width: 100px;
|
|
1100
|
+
|
|
1101
|
+
.el-select__wrapper {
|
|
1102
|
+
background: #3c3c3c;
|
|
1103
|
+
box-shadow: none;
|
|
1104
|
+
min-height: 24px;
|
|
1105
|
+
padding: 0 8px;
|
|
1106
|
+
|
|
1107
|
+
.el-select__placeholder {
|
|
1108
|
+
color: #969696;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
.el-select__selected-item {
|
|
1112
|
+
color: #d4d4d4;
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
.separator {
|
|
1119
|
+
color: #969696;
|
|
1120
|
+
font-size: 12px;
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
.insert-btn {
|
|
1125
|
+
width: 100%;
|
|
1126
|
+
margin-top: 4px;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
.variable-footer {
|
|
1133
|
+
padding: 6px 12px;
|
|
1134
|
+
background: #2d2d30;
|
|
1135
|
+
border-top: 1px solid #444;
|
|
1136
|
+
font-size: 11px;
|
|
1137
|
+
color: #969696;
|
|
1138
|
+
text-align: center;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
470
1141
|
</style>
|