feat(assets): 资产页新增「应用」Tab + app 字段可搜
- 资产页 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 <[email protected]>
This commit is contained in:
1 parent
6d8fa5bc48
commit
e01b659097
2 files changed
+54
-7
No files matched your search
+10
-7
@@ -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 {
|
||||
|
||||
@@ -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() {
|
||||
</AssetCard>
|
||||
</TabsContent>
|
||||
|
||||
{/* 应用 */}
|
||||
<TabsContent value="app" className="mt-0 flex min-h-0 flex-1 flex-col gap-2">
|
||||
{searchBox}
|
||||
<AssetCard
|
||||
cols={["", "应用名", "Bundle ID", "分类", "ICP 备案", ""]}
|
||||
loaded={loaded}
|
||||
total={total}
|
||||
page={page}
|
||||
size={size}
|
||||
onSize={setSize}
|
||||
onPage={setPage}
|
||||
rows={rows}
|
||||
selected={selected}
|
||||
onToggleAll={(ids) => toggleSelectAll(ids)}
|
||||
>
|
||||
{slice(tabData("app")).map((a) => (
|
||||
<TableRow key={a.id} className={selected.has(a.id) ? "bg-muted/40" : undefined}>
|
||||
<TableCell className="w-8 pr-0">
|
||||
<Checkbox checked={selected.has(a.id)} onCheckedChange={() => toggleSelect(a.id)} />
|
||||
</TableCell>
|
||||
<TableCell className="text-xs font-medium">{a.app_name || "—"}</TableCell>
|
||||
<TableCell className="font-mono text-xs">{a.bundle_id || "—"}</TableCell>
|
||||
<TableCell className="text-xs">{a.category || "—"}</TableCell>
|
||||
<TableCell className="text-xs">{a.app_icp || "—"}</TableCell>
|
||||
<TableCell className="w-8 pl-0">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-7 text-muted-foreground hover:text-destructive"
|
||||
onClick={() => openDelete([a.id])}
|
||||
>
|
||||
<Trash2Icon className="size-3.5" />
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</AssetCard>
|
||||
</TabsContent>
|
||||
|
||||
{/* 服务 */}
|
||||
<TabsContent value="service" className="mt-0 flex min-h-0 flex-1 flex-col gap-2">
|
||||
{searchBox}
|
||||
|
||||
Reference in new issue
Block a user