日志改常驻收集,加清空按钮;原生 select 统一换成 SelectBox

日志收集从请求页组件搬进模块级单例(web/log-store.ts,模式同 telemetry),
切走页面不再清空;离线时保留已收的日志,只提示不再更新。清空只清界面。

五处原生 <select> 在三个文件里各自重复同一套自绘箭头样式,而且原生控件
没有「展开中」状态可读,箭头做不了开合动画——提成 SelectBox 组件统一替换:
箭头随开合旋转 180 度,弹层带出入场动画,下方视口不够时向上弹。背景色
留 --select-bg 口子,对话框里沉一档、页面上浮一档,一个值满足不了两边。
This commit is contained in:
2026-08-11 23:47:28 +08:00
parent 60fb015e36
commit f927f9fff7
7 changed files with 473 additions and 187 deletions
+15 -23
View File
@@ -12,6 +12,8 @@ import { computed, ref, watch } from 'vue'
import type { Inbound } from '@shared/inbounds.ts'
import type { FieldSpec, ListenerFields } from '../api'
import type { ConfigObject } from '../../vendor/config-editor/index.ts'
import SelectBox from '../components/SelectBox.vue'
import type { SelectItem } from '../components/SelectBox.vue'
import IconClose from '~icons/ri/close-line'
const props = defineProps<{
@@ -42,6 +44,11 @@ const extras = ref<Record<string, string>>({})
const allTypes = computed(() => Object.keys(props.fields?.types ?? {}))
const serverTypes = computed(() => allTypes.value.filter((t) => !COMMON_TYPES.includes(t)))
const typeOptions = computed<SelectItem[]>(() => [
...COMMON_TYPES.map((t) => ({ value: t, group: '客户端入站' })),
...serverTypes.value.map((t) => ({ value: t, group: '服务端入站' })),
])
/** 当前类型的必填字段,公共字段之外的那些。 */
const requiredExtras = computed<FieldSpec[]>(
() => props.fields?.types[type.value]?.fields.filter((f) => f.required && !f.key.includes('.')) ?? [],
@@ -139,14 +146,7 @@ function submit() {
<label class="row">
<span class="k">类型</span>
<span class="v">
<select v-model="type">
<optgroup label="客户端入站">
<option v-for="t in COMMON_TYPES" :key="t" :value="t">{{ t }}</option>
</optgroup>
<optgroup label="服务端入站">
<option v-for="t in serverTypes" :key="t" :value="t">{{ t }}</option>
</optgroup>
</select>
<SelectBox v-model="type" :options="typeOptions" />
<span v-if="typeNote" class="note">{{ typeNote }}</span>
</span>
</label>
@@ -170,10 +170,12 @@ function submit() {
<label v-for="f in requiredExtras" :key="f.key" class="row">
<span class="k">{{ f.key }}</span>
<span class="v">
<select v-if="f.enum" v-model="extras[f.key]">
<option value="" disabled>请选择</option>
<option v-for="opt in f.enum" :key="String(opt)" :value="String(opt)">{{ opt }}</option>
</select>
<SelectBox
v-if="f.enum"
v-model="extras[f.key]"
:options="f.enum.map((opt) => ({ value: String(opt) }))"
placeholder="请选择"
/>
<input v-else v-model="extras[f.key]" class="mono" type="text" autocomplete="off" />
<span v-if="f.note" class="note">{{ f.note }}</span>
</span>
@@ -262,8 +264,7 @@ function submit() {
min-width: 0;
}
input,
select {
input {
width: 100%;
padding: var(--s-2) var(--s-3);
border: 1px solid var(--c-border-strong);
@@ -271,15 +272,6 @@ select {
background: var(--c-bg);
}
/* 自绘下拉箭头:原生箭头贴着右边缘,位置调不了。灰色取两套主题中间值 */
select {
appearance: none;
padding-right: var(--s-6);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='16' height='16'%3E%3Cpath fill='%23898f98' d='M12 15.6 5.7 9.3l1.4-1.4 4.9 4.9 4.9-4.9 1.4 1.4z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right var(--s-3) center;
}
.note {
font-size: var(--t-xs);
color: var(--c-text-faint);