diff --git a/CHANGELOG.md b/CHANGELOG.md
index ccc2d98..36be7b4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,12 +1,12 @@
+
# Changelog
# [1.1.0](https://github.com/perfect-panel/ppanel-web/compare/v1.0.2...v1.1.0) (2025-07-06)
-
### ✨ Features
-* **view**: Add AnyTLS protocol support and enhance node configuration options ([bcfb10a](https://github.com/perfect-panel/ppanel-web/commit/bcfb10a))
+- **view**: Add AnyTLS protocol support and enhance node configuration options ([bcfb10a](https://github.com/perfect-panel/ppanel-web/commit/bcfb10a))
diff --git a/apps/admin/app/dashboard/rules/import-yaml-rules.tsx b/apps/admin/app/dashboard/rules/import-yaml-rules.tsx
index 7ac6434..57d029d 100644
--- a/apps/admin/app/dashboard/rules/import-yaml-rules.tsx
+++ b/apps/admin/app/dashboard/rules/import-yaml-rules.tsx
@@ -88,12 +88,32 @@ export default function ImportYamlRules({ onImportSuccess }: ImportYamlRulesProp
if (!groups[policyGroup]) {
groups[policyGroup] = [];
}
- groups[policyGroup].push(cleanRule);
+
+ // 不插入 MATCH 规则,只用于标识默认规则组
+ if (!rule.trim().startsWith('MATCH,')) {
+ groups[policyGroup].push(cleanRule);
+ }
}
return groups;
};
+ const checkIfDefaultRule = (originalRules: string[], groupName: string): boolean => {
+ return originalRules.some((rule) => {
+ const trimmedRule = rule.trim();
+ if (!trimmedRule.startsWith('MATCH,')) return false;
+
+ // 检查 MATCH 规则是否属于当前组
+ const parts = trimmedRule.split(',');
+ if (parts.length >= 3) {
+ const ruleGroup = parts[2]?.trim();
+ return ruleGroup === groupName;
+ }
+
+ return groupName === 'default';
+ });
+ };
+
const handleImport = async () => {
if (!yamlContent) {
toast.error(t('pleaseUploadFile'));
@@ -130,12 +150,17 @@ export default function ImportYamlRules({ onImportSuccess }: ImportYamlRulesProp
for (let i = 0; i < groups.length; i++) {
const group = groups[i];
if (!group?.name || !group?.rules.length) continue;
+
+ const isDefault = checkIfDefaultRule(allRules, group.name);
+
await createRuleGroup({
name: group.name,
rules: group?.rules.join('\n'),
enable: false,
tags: [],
icon: '',
+ type: 'auto',
+ default: isDefault,
});
setImportProgress(i + 1);
}
diff --git a/apps/admin/app/dashboard/rules/page.tsx b/apps/admin/app/dashboard/rules/page.tsx
index 08d265d..b2f2458 100644
--- a/apps/admin/app/dashboard/rules/page.tsx
+++ b/apps/admin/app/dashboard/rules/page.tsx
@@ -50,6 +50,8 @@ export default function Page() {
enable: false,
tags: values.tags || [],
icon: values.icon || '',
+ type: values.type || 'auto',
+ default: false,
});
toast.success(t('createSuccess'));
ref.current?.refresh();
@@ -99,6 +101,22 @@ export default function Page() {
);
},
},
+ {
+ accessorKey: 'default',
+ header: t('defaultRule'),
+ cell: ({ row }) => (
+ {
+ await updateRuleGroup({
+ ...row.original,
+ default: checked,
+ } as API.UpdateRuleGroupRequest);
+ ref.current?.refresh();
+ }}
+ />
+ ),
+ },
{
accessorKey: 'icon',
header: t('appIcon'),
@@ -122,6 +140,16 @@ export default function Page() {
accessorKey: 'name',
header: t('name'),
},
+ {
+ accessorKey: 'type',
+ header: t('type'),
+ cell: ({ row }) => {
+ const type = row.original.type;
+ if (type === 'auto') return t('auto');
+ if (type === 'ban') return t('ban');
+ return type || '--';
+ },
+ },
{
accessorKey: 'tags',
header: t('tags'),
@@ -163,6 +191,8 @@ export default function Page() {
rules: values.rules,
enable: row.enable,
icon: values.icon,
+ type: values.type,
+ default: row.default,
});
toast.success(t('updateSuccess'));
ref.current?.refresh();
diff --git a/apps/admin/app/dashboard/rules/rule-form.tsx b/apps/admin/app/dashboard/rules/rule-form.tsx
index 695b34e..8796e04 100644
--- a/apps/admin/app/dashboard/rules/rule-form.tsx
+++ b/apps/admin/app/dashboard/rules/rule-form.tsx
@@ -13,6 +13,13 @@ import {
FormMessage,
} from '@workspace/ui/components/form';
import { ScrollArea } from '@workspace/ui/components/scroll-area';
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@workspace/ui/components/select';
import {
Sheet,
SheetContent,
@@ -36,6 +43,7 @@ const formSchema = z.object({
tags: z.array(z.string()).default([]),
rules: z.string().default(''),
icon: z.string().default(''),
+ type: z.string().default('auto'),
});
interface RuleFormProps {
@@ -147,6 +155,32 @@ export default function RuleForm>({
)}
/>
+ (
+
+ {t('type')}
+
+
+
+
+
+ )}
+ />