规则编辑:建议列表全量展开,目标补齐候选,删除免确认

组合框展开先给全量、本次展开输入过才过滤——按当前值过滤的话,预填的
类型会把列表滤到只剩它自己,MATCH 这类排在后面的选项等于不存在。类型
因此可以默认留空,placeholder 当示例。

目标建议由页面传入:全局规则给内置两个加用户自建的组和自有线路;附加
规则多一项本路专属组——「这个载荷走本路代理」写的就是它,放在拦截规则
前面还能做豁免。生成的专属组不列,每路三个会把列表灌成一面墙。

原文/字段切换只拦真正整行编辑的类型(isRawOnlyRule):之前用
isStructuredEditable 拦,新增时的空原文永远过不了,卡死在原文模式。

删除规则和附加规则不再二次确认——删错了有撤回,确认框只是多一步;
toast 带上被删规则的原文。
This commit is contained in:
2026-08-12 13:16:58 +08:00
parent 955fa340af
commit 48e97bd91f
6 changed files with 80 additions and 55 deletions
+11 -12
View File
@@ -8,7 +8,7 @@
* 列出来的多得多。
*/
import { computed, ref, watch } from 'vue'
import { buildRule, isStructuredEditable, parseRule } from '@shared/rules.ts'
import { buildRule, isRawOnlyRule, isStructuredEditable, parseRule } from '@shared/rules.ts'
import ComboBox from '../components/ComboBox.vue'
import IconClose from '~icons/ri/close-line'
@@ -18,6 +18,8 @@ const props = defineProps<{
editing: { index: number; raw: string } | null
/** RULE-SET 载荷的候选:已声明的规则组 */
providerNames: string[]
/** 目标的建议。只是建议,手填任何出站名都合法 */
targetOptions: string[]
saving: boolean
}>()
@@ -67,16 +69,10 @@ const RULE_TYPES = [
'MATCH',
]
/**
* 目标的建议只给内置出站里日常用的两个。策略组名允许手填——
* 全部列出来的话,每路入站自动生成的三个专属组会把列表灌成一面墙。
*/
const TARGET_SUGGESTIONS = ['DIRECT', 'REJECT']
const dialog = ref<HTMLDialogElement | null>(null)
const rawMode = ref(false)
const raw = ref('')
const type = ref('DOMAIN-SUFFIX')
const type = ref('')
const payload = ref('')
const target = ref('')
const extras = ref('')
@@ -115,7 +111,8 @@ watch(
} else {
rawMode.value = false
const parsed = parseRule(source)
type.value = parsed.type || 'DOMAIN-SUFFIX'
// 新增时留空:预填的类型会把下拉的建议过滤到只剩它自己
type.value = parsed.type
payload.value = parsed.payload ?? ''
target.value = parsed.target ?? ''
extras.value = parsed.extras.join(',')
@@ -131,7 +128,9 @@ watch(
function toggleMode() {
if (rawMode.value) {
const line = raw.value.trim()
if (!isStructuredEditable(line)) return
// 只有逻辑规则这类整行编辑的类型留在原文模式;空行、没写完的行都带回表单
// 接着填——按 isStructuredEditable 拦的话,新增时的空原文会让人永远切不回去
if (isRawOnlyRule(line)) return
const parsed = parseRule(line)
type.value = parsed.type
payload.value = parsed.payload ?? ''
@@ -189,7 +188,7 @@ function onBackdrop(event: MouseEvent) {
<label class="row">
<span class="k">类型</span>
<span class="v">
<ComboBox v-model="type" mono :options="RULE_TYPES" />
<ComboBox v-model="type" mono :options="RULE_TYPES" placeholder="DOMAIN-SUFFIX" />
</span>
</label>
@@ -218,7 +217,7 @@ function onBackdrop(event: MouseEvent) {
<label class="row">
<span class="k">目标</span>
<span class="v">
<ComboBox v-model="target" mono :options="TARGET_SUGGESTIONS" placeholder="DIRECT" />
<ComboBox v-model="target" mono :options="targetOptions" placeholder="DIRECT" />
</span>
</label>