From e01b659097c950c4b184e84b717953a3f3313198 Mon Sep 17 00:00:00 2001 From: Autumn-27 <53844290+Autumn-27@users.noreply.github.com> Date: Sat, 8 Aug 2026 06:19:11 -0400 Subject: [PATCH] =?UTF-8?q?feat(assets):=20=E8=B5=84=E4=BA=A7=E9=A1=B5?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E3=80=8C=E5=BA=94=E7=94=A8=E3=80=8DTab=20+?= =?UTF-8?q?=20app=20=E5=AD=97=E6=AE=B5=E5=8F=AF=E6=90=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 资产页 TABS 补 app 分类,新增应用列表(应用名/Bundle ID/分类/ICP 备案)+勾选/删除 - DSL 搜索白名单补 bundle_id/category/app_icp(原仅 app_name),前端搜索建议同步 - list/count 本就按 type 通用,app 自动适配;补齐后 app 资产可看/可搜/可删 Co-Authored-By: Claude Opus 4.8 --- db/asset_dsl.go | 17 ++++---- web/src/app/(main)/function/assets/page.tsx | 44 +++++++++++++++++++++ 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/db/asset_dsl.go b/db/asset_dsl.go index b708c33..24c7f25 100644 --- a/db/asset_dsl.go +++ b/db/asset_dsl.go @@ -37,6 +37,9 @@ var knownStringFields = map[string]string{ "icp": "icp", "service_name": "service_name", "app_name": "app_name", + "bundle_id": "bundle_id", + "category": "category", + "app_icp": "app_icp", "method": "method", "service_type": "service_type", "record_type": "record_type", @@ -67,13 +70,13 @@ func isKnownField(f string) bool { // ── tokeniser ──────────────────────────────────────────────────────────────── const ( - tkField = "FIELD" - tkBare = "BARE" - tkAnd = "AND" - tkOr = "OR" - tkLP = "LPAREN" - tkRP = "RPAREN" - tkEOF = "EOF" + tkField = "FIELD" + tkBare = "BARE" + tkAnd = "AND" + tkOr = "OR" + tkLP = "LPAREN" + tkRP = "RPAREN" + tkEOF = "EOF" ) type tok struct { diff --git a/web/src/app/(main)/function/assets/page.tsx b/web/src/app/(main)/function/assets/page.tsx index 9712f50..b1892d4 100644 --- a/web/src/app/(main)/function/assets/page.tsx +++ b/web/src/app/(main)/function/assets/page.tsx @@ -7,6 +7,7 @@ import { NetworkIcon, LayoutTemplateIcon, LinkIcon, + SmartphoneIcon, SearchIcon, KeyRoundIcon, ChevronLeftIcon, @@ -76,6 +77,9 @@ const DSL_FIELDS: { name: string; desc: string; ops: { op: string; desc: string { name: "icp", desc: "ICP 备案号", ops: [{ op: "=", desc: "模糊匹配" }, { op: "==", desc: "精确匹配" }, { op: "!=", desc: "排除" }] }, { name: "service_name", desc: "服务名称(非 HTTP 服务)", ops: [{ op: "=", desc: "模糊匹配" }, { op: "==", desc: "精确匹配" }, { op: "!=", desc: "排除" }] }, { name: "app_name", desc: "应用名称", ops: [{ op: "=", desc: "模糊匹配" }, { op: "==", desc: "精确匹配" }, { op: "!=", desc: "排除" }] }, + { name: "bundle_id", desc: "应用 Bundle ID", ops: [{ op: "=", desc: "模糊匹配" }, { op: "==", desc: "精确匹配" }, { op: "!=", desc: "排除" }] }, + { name: "category", desc: "应用分类", ops: [{ op: "=", desc: "模糊匹配" }, { op: "==", desc: "精确匹配" }, { op: "!=", desc: "排除" }] }, + { name: "app_icp", desc: "应用 ICP 备案", ops: [{ op: "=", desc: "模糊匹配" }, { op: "==", desc: "精确匹配" }, { op: "!=", desc: "排除" }] }, { name: "method", desc: "HTTP 方法 GET/POST/PUT/…", ops: [{ op: "==", desc: "精确匹配" }, { op: "!=", desc: "排除" }] }, { name: "service_type", desc: "服务类型:http | other", ops: [{ op: "==", desc: "精确匹配" }, { op: "!=", desc: "排除" }] }, { name: "record_type", desc: "DNS 解析类型 A/CNAME/MX/…", ops: [{ op: "==", desc: "精确匹配" }, { op: "!=", desc: "排除" }] }, @@ -216,6 +220,7 @@ const TABS: { key: string; label: string; icon: LucideIcon }[] = [ { key: "root_domain", label: "根域名", icon: GlobeIcon }, { key: "ip", label: "IP", icon: NetworkIcon }, { key: "subdomain", label: "子域名", icon: GlobeIcon }, + { key: "app", label: "应用", icon: SmartphoneIcon }, { key: "service", label: "服务", icon: LayoutTemplateIcon }, { key: "endpoint", label: "接口", icon: LinkIcon }, ]; @@ -609,6 +614,45 @@ export default function AssetsPage() { + {/* 应用 */} + + {searchBox} + toggleSelectAll(ids)} + > + {slice(tabData("app")).map((a) => ( + + + toggleSelect(a.id)} /> + + {a.app_name || "—"} + {a.bundle_id || "—"} + {a.category || "—"} + {a.app_icp || "—"} + + + + + ))} + + + {/* 服务 */} {searchBox}