Skip to content

Commit dcf47b3

Browse files
committed
feat: 新增脚本操作中的参数编辑组件
1 parent 9a53631 commit dcf47b3

File tree

5 files changed

+423
-226
lines changed

5 files changed

+423
-226
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sub-store-front-end",
3-
"version": "2.15.0",
3+
"version": "2.15.1",
44
"private": true,
55
"scripts": {
66
"dev": "vite --host",

src/components/ParamsEditor.vue

+250
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
<template>
2+
<div>
3+
<div v-if="visible" class="key-value-container">
4+
<div class="key-value-box">
5+
<div class="header">
6+
<div class="item">key</div>
7+
<div class="item">value</div>
8+
<div class="item">{{ optionsText }}</div>
9+
</div>
10+
<div class="content">
11+
<div
12+
v-for="(item, index) in paramsArgumentsLocal"
13+
:key="index"
14+
class="key-value-row"
15+
:class="{ 'duplicate-key-row': isDuplicateKey(item.key) }"
16+
>
17+
<div class="item">
18+
<div class="input-container">
19+
<nut-textarea
20+
v-model="item.key"
21+
:border="false"
22+
placeholder="key"
23+
type="text"
24+
:rows="1"
25+
autosize
26+
:class="{ 'duplicate-key-input': isDuplicateKey(item.key) }"
27+
@blur="handleKeyBlur(item, index)"
28+
/>
29+
<div
30+
v-if="isDuplicateKey(item.key) && item.key"
31+
class="duplicate-key-tip"
32+
>
33+
{{
34+
$t(`editorPage.subConfig.nodeActions['${props.type}'].duplicateKeyWarning`)
35+
}}
36+
</div>
37+
</div>
38+
</div>
39+
<div class="item">
40+
<nut-textarea
41+
v-model="item.value"
42+
:border="false"
43+
placeholder="value"
44+
type="text"
45+
:rows="1"
46+
autosize
47+
@blur="trimValue(item, 'value')"
48+
/>
49+
</div>
50+
<div class="item key-value-operation">
51+
<div @click="deleteItem(index)">{{ deleteParamsText }}</div>
52+
</div>
53+
</div>
54+
<div v-if="!paramsArgumentsLocal.length" class="empty-tips">
55+
<p>{{ emptyTipsText }}</p>
56+
</div>
57+
</div>
58+
</div>
59+
</div>
60+
</div>
61+
</template>
62+
63+
<script lang="ts" setup>
64+
import { computed, ref, watch } from "vue";
65+
import { useI18n } from "vue-i18n";
66+
67+
type ParamItem = {
68+
key: string;
69+
value: string;
70+
};
71+
72+
const props = defineProps({
73+
paramsArguments: {
74+
type: Array as () => ParamItem[],
75+
default: () => [],
76+
},
77+
visible: {
78+
type: Boolean,
79+
default: false,
80+
},
81+
type: {
82+
type: String,
83+
required: true,
84+
},
85+
});
86+
87+
const emit = defineEmits(["update:paramsArguments", "add-parameter"]);
88+
89+
const { t } = useI18n();
90+
91+
const paramsArgumentsLocal = computed({
92+
get: () => props.paramsArguments as ParamItem[],
93+
set: (val: ParamItem[]) => emit("update:paramsArguments", val),
94+
});
95+
96+
// 跟踪重复键
97+
const keyOccurrences = ref<Record<string, number>>({});
98+
99+
// 更新键名出现次数的函数
100+
const updateKeyOccurrences = (args) => {
101+
const occurrences = {};
102+
args.forEach((item) => {
103+
if (item.key && item.key.trim() !== "") {
104+
occurrences[item.key] = (occurrences[item.key] || 0) + 1;
105+
}
106+
});
107+
keyOccurrences.value = occurrences;
108+
};
109+
110+
// 检查一个键名是否重复
111+
const isDuplicateKey = (key) => {
112+
return key && keyOccurrences.value[key] > 1;
113+
};
114+
115+
// 监听参数变化,更新重复键的计数
116+
watch(
117+
() => props.paramsArguments,
118+
(newArgs) => {
119+
updateKeyOccurrences(newArgs);
120+
},
121+
{ deep: true, immediate: true },
122+
);
123+
124+
// 文本内容通过i18n翻译
125+
const optionsText = computed(() =>
126+
t(`editorPage.subConfig.nodeActions['${props.type}'].paramsOptions`),
127+
);
128+
const deleteParamsText = computed(() =>
129+
t(`editorPage.subConfig.nodeActions['${props.type}'].paramsDelete`),
130+
);
131+
const emptyTipsText = computed(() =>
132+
t(`editorPage.subConfig.nodeActions['${props.type}'].paramsEmpty`),
133+
);
134+
135+
const deleteItem = (index) => {
136+
const newParamsArguments = [...props.paramsArguments];
137+
newParamsArguments.splice(index, 1);
138+
emit("update:paramsArguments", newParamsArguments);
139+
// 删除后需要更新键名出现次数
140+
updateKeyOccurrences(newParamsArguments);
141+
};
142+
143+
const trimValue = (item, field) => {
144+
if (item[field] && typeof item[field] === "string") {
145+
item[field] = item[field].replace(/\s+/g, "");
146+
}
147+
};
148+
149+
// 处理键名失焦事件
150+
const handleKeyBlur = (item, index) => {
151+
// 先去除空白符
152+
trimValue(item, "key");
153+
154+
// 更新键名出现次数统计
155+
updateKeyOccurrences(props.paramsArguments);
156+
};
157+
</script>
158+
159+
<style lang="scss" scoped>
160+
.key-value-container {
161+
border-radius: var(--item-card-radios);
162+
overflow: hidden;
163+
.key-value-box {
164+
.header {
165+
display: grid;
166+
grid-template-columns: 2fr 2fr 1fr;
167+
font-size: 14px;
168+
color: var(--second-text-color);
169+
padding: 8px 0;
170+
border-bottom: 1px solid var(--lowest-text-color);
171+
.item {
172+
text-align: left;
173+
padding: 8px 12px;
174+
&:last-child {
175+
text-align: center;
176+
}
177+
}
178+
}
179+
.content {
180+
.key-value-row {
181+
display: grid;
182+
grid-template-columns: 2fr 2fr 1fr;
183+
padding: 8px 0;
184+
185+
&.duplicate-key-row {
186+
background-color: rgba(255, 68, 68, 0.05); // 重复键行的背景色
187+
}
188+
189+
.item {
190+
text-align: left;
191+
display: flex;
192+
align-items: flex-start; // 改为顶部对齐,方便显示错误提示
193+
194+
.input-container {
195+
width: 100%;
196+
display: flex;
197+
flex-direction: column;
198+
199+
.duplicate-key-tip {
200+
font-size: 10px;
201+
color: var(--danger-color, #ff4444);
202+
padding: 2px 12px;
203+
margin-top: -2px;
204+
}
205+
}
206+
207+
:deep(.nut-textarea) {
208+
width: 100%;
209+
background: transparent;
210+
padding: 8px 12px;
211+
color: var(--second-text-color);
212+
213+
&.duplicate-key-input {
214+
// border-bottom: 1px solid var(--danger-color, #ff4444);
215+
color: var(--danger-color, #ff4444);
216+
}
217+
218+
:deep(.nut-textarea__textarea) {
219+
color: inherit;
220+
min-height: unset;
221+
height: auto;
222+
overflow: hidden;
223+
}
224+
}
225+
226+
&.key-value-operation {
227+
display: flex;
228+
align-items: center;
229+
justify-content: center;
230+
div {
231+
cursor: pointer;
232+
color: var(--primary-color);
233+
margin: 0 8px;
234+
}
235+
}
236+
}
237+
}
238+
.empty-tips {
239+
display: flex;
240+
justify-content: center;
241+
padding: 8px 0;
242+
color: var(--comment-text-color);
243+
p {
244+
font-size: 12px;
245+
}
246+
}
247+
}
248+
}
249+
}
250+
</style>

src/locales/en.ts

+4
Original file line numberDiff line numberDiff line change
@@ -540,10 +540,14 @@ export default {
540540
tipsDes: "Use a JavaScript script to filter nodes",
541541
paramsEdit: 'Edit Parameters',
542542
noCache: 'noCache',
543+
helpTitle: 'noCache Tips',
544+
noCacheTips: 'When the cache is turned off, the script is refetched for each request.',
545+
paramsEditTips: 'Visual parameter editor, duplicate key names will adopt the principle of prioritizing the latter value.',
543546
paramsAdd: 'Add',
544547
paramsDelete: 'Delete',
545548
paramsOptions: 'Options',
546549
paramsEmpty: 'No parameters',
550+
duplicateKeyWarning: 'Duplicate key names',
547551
},
548552
},
549553
sourceNamePicker: {

src/locales/zh.ts

+4
Original file line numberDiff line numberDiff line change
@@ -419,10 +419,14 @@ export default {
419419
tipsDes: '使用一段 JavaScript 脚本来修改节点信息',
420420
paramsEdit: '参数编辑',
421421
noCache: '关闭缓存',
422+
helpTitle: '温馨提示',
423+
noCacheTips: '关闭缓存后, 每次请求都会重新获取脚本内容',
424+
paramsEditTips: '可视化参数编辑器,重复键名将采用后值优先原则',
422425
paramsAdd: '添加参数',
423426
paramsDelete: '删除',
424427
paramsOptions: '操作',
425428
paramsEmpty: '暂无参数数据',
429+
duplicateKeyWarning: '重复的键名',
426430
},
427431
'Flag Operator': {
428432
label: '旗帜操作',

0 commit comments

Comments
 (0)