feat: 智能体与技能列表显示创建时间字段
- 新增共享 formatDateTime 工具(YYYY-MM-DD HH:mm) - agent-card 卡片/列表视图在发布者下方显示创建时间 - skill 设置页 metaNodes 显示创建时间 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
595da9f339
commit
74113b3e6e
3 files changed
+39
No files matched your search
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
BotIcon,
|
BotIcon,
|
||||||
|
ClockIcon,
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
EyeOffIcon,
|
EyeOffIcon,
|
||||||
GlobeIcon,
|
GlobeIcon,
|
||||||
@@ -78,6 +79,7 @@ import type { Agent, AgentQuestion, UpdateAgentRequest } from "@/core/agents";
|
|||||||
import { getStoredAuth } from "@/core/auth";
|
import { getStoredAuth } from "@/core/auth";
|
||||||
import { useI18n } from "@/core/i18n/hooks";
|
import { useI18n } from "@/core/i18n/hooks";
|
||||||
import { useSkills } from "@/core/skills/hooks";
|
import { useSkills } from "@/core/skills/hooks";
|
||||||
|
import { formatDateTime } from "@/core/utils/datetime";
|
||||||
import { desensitize } from "@/lib/desensitize";
|
import { desensitize } from "@/lib/desensitize";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
@@ -605,6 +607,17 @@ export function AgentCard({ agent, layout = "card", onPublisherClick }: AgentCar
|
|||||||
</button>
|
</button>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
|
const createdAtText = formatDateTime(agent.created_at);
|
||||||
|
const createdAtNode = createdAtText ? (
|
||||||
|
<div
|
||||||
|
className="text-muted-foreground flex max-w-full items-center gap-1 text-xs"
|
||||||
|
title={`创建时间:${createdAtText}`}
|
||||||
|
>
|
||||||
|
<ClockIcon className="size-3.5 shrink-0" />
|
||||||
|
<span className="truncate">创建时间:{createdAtText}</span>
|
||||||
|
</div>
|
||||||
|
) : null;
|
||||||
|
|
||||||
// 技能英文名 → 中文名映射,用于把智能体的技能徽章显示为中文(agent.skills 只存英文名)。
|
// 技能英文名 → 中文名映射,用于把智能体的技能徽章显示为中文(agent.skills 只存英文名)。
|
||||||
const skillNameZhMap = useMemo(() => {
|
const skillNameZhMap = useMemo(() => {
|
||||||
const map = new Map<string, string>();
|
const map = new Map<string, string>();
|
||||||
@@ -820,6 +833,7 @@ export function AgentCard({ agent, layout = "card", onPublisherClick }: AgentCar
|
|||||||
</CardDescription>
|
</CardDescription>
|
||||||
)}
|
)}
|
||||||
{publisherNode && <div className="mt-2">{publisherNode}</div>}
|
{publisherNode && <div className="mt-2">{publisherNode}</div>}
|
||||||
|
{createdAtNode && <div className="mt-1">{createdAtNode}</div>}
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
{(agent.tags?.length ?? 0) > 0 && (
|
{(agent.tags?.length ?? 0) > 0 && (
|
||||||
@@ -866,6 +880,7 @@ export function AgentCard({ agent, layout = "card", onPublisherClick }: AgentCar
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{publisherNode && <div className="mt-0.5">{publisherNode}</div>}
|
{publisherNode && <div className="mt-0.5">{publisherNode}</div>}
|
||||||
|
{createdAtNode && <div className="mt-0.5">{createdAtNode}</div>}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex shrink-0 items-center gap-1">
|
<div className="flex shrink-0 items-center gap-1">
|
||||||
{showActionRow && actionButtons}
|
{showActionRow && actionButtons}
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ import {
|
|||||||
} from "@/core/skills/hooks";
|
} from "@/core/skills/hooks";
|
||||||
import { usePublishSquares, useViewMode } from "@/core/system-settings/hooks";
|
import { usePublishSquares, useViewMode } from "@/core/system-settings/hooks";
|
||||||
import type { Skill } from "@/core/skills/type";
|
import type { Skill } from "@/core/skills/type";
|
||||||
|
import { formatDateTime } from "@/core/utils/datetime";
|
||||||
import { env } from "@/env";
|
import { env } from "@/env";
|
||||||
import { desensitize } from "@/lib/desensitize";
|
import { desensitize } from "@/lib/desensitize";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
@@ -848,6 +849,14 @@ export function SkillRow({
|
|||||||
: t.settings.skills.useCountInlineZero}
|
: t.settings.skills.useCountInlineZero}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{formatDateTime(skill.created_at) && (
|
||||||
|
<div className="text-muted-foreground mt-1 flex items-center gap-1 text-xs">
|
||||||
|
<ClockIcon className="size-3.5 shrink-0" />
|
||||||
|
<span className="truncate">
|
||||||
|
创建时间:{formatDateTime(skill.created_at)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{(skill.tags?.length ?? 0) > 0 && (
|
{(skill.tags?.length ?? 0) > 0 && (
|
||||||
<TagChipList tags={skill.tags!} className="mt-2" />
|
<TagChipList tags={skill.tags!} className="mt-2" />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -25,3 +25,18 @@ export function formatTimeAgo(date: Date | string | number, locale?: Locale) {
|
|||||||
locale: getDateFnsLocale(effectiveLocale),
|
locale: getDateFnsLocale(effectiveLocale),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a created/updated timestamp as `YYYY-MM-DD HH:mm`.
|
||||||
|
* Returns an empty string for missing or unparseable values.
|
||||||
|
*/
|
||||||
|
export function formatDateTime(value?: Date | string | number | null): string {
|
||||||
|
if (value === null || value === undefined || value === "") return "";
|
||||||
|
const date = value instanceof Date ? value : new Date(value);
|
||||||
|
if (Number.isNaN(date.getTime())) return "";
|
||||||
|
const pad = (n: number) => String(n).padStart(2, "0");
|
||||||
|
return (
|
||||||
|
`${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` +
|
||||||
|
`${pad(date.getHours())}:${pad(date.getMinutes())}`
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user