feat: 可配置站点 URL 风格

- 新增 urlStyle 工具与测试:postPath/userPath/sitePagePath 统一生成链接
- 管理端新增 UrlStylePanel 设置面板,settings 服务与 handler 适配
- 全站路由链接与 JSON-LD/sitemap 切换为统一 URL 生成
- middleware 与相关组件适配
This commit is contained in:
2026-09-27 04:01:42 +08:00
parent 1d862a0dd3
commit 7a44c1f2cf
64 changed files with 1183 additions and 200 deletions

View File

@@ -9,6 +9,8 @@ import { pointReasonLabel } from "@/lib/points";
import { formatRelative } from "@/lib/format";
import { AdminPageHeader, AdminSegmented, AdminStatCard } from "@/components/admin";
import Avatar from "@/components/Avatar";
import { useUrlStyle } from "@/components/SiteBrandProvider";
import { userPath } from "@/lib/urlStyle";
import {
AdminChartCard,
DeltaBarChart,
@@ -326,10 +328,11 @@ function StockOverviewCard({ stats }: { stats: EconomyStats }) {
}
function LedgerUserLink({ user, compact }: { user: LedgerParty; compact?: boolean }) {
const urlStyle = useUrlStyle();
const name = partyName(user);
return (
<Link
href={`/u/${user.id}`}
href={userPath(urlStyle, user.id)}
className="flex items-center gap-1.5 min-w-0 max-w-[128px] rounded-md hover:bg-[var(--panel-2)] -mx-0.5 px-0.5 py-0.5 transition-colors"
title={`${name} @${user.username}`}
>

View File

@@ -17,6 +17,8 @@ import { AdminPageHeader, AdminPager, AdminSearchField, AdminStepper } from "@/c
import { pointReasonLabel } from "@/lib/points";
import { formatRelative } from "@/lib/format";
import { toast } from "@/lib/toast";
import { userPath } from "@/lib/urlStyle";
import { useUrlStyle } from "@/components/SiteBrandProvider";
const PAGE_SIZE = 20;
const MAX_DELTA = 100000; // 与后端 adminAdjustMaxDelta 一致
@@ -72,6 +74,7 @@ function SortHeader({
* 扣分仅扣余额不降级,理由必填)与「流水」弹窗(分页查看该用户积分流水)。
*/
export default function UserPointsTab() {
const urlStyle = useUrlStyle();
const [keyword, setKeyword] = useState("");
const [appliedQ, setAppliedQ] = useState("");
const [page, setPage] = useState(1);
@@ -209,7 +212,7 @@ export default function UserPointsTab() {
{users.map((u) => (
<tr key={u.id} style={{ borderBottom: "1px solid var(--line)" }}>
<td className="px-4 py-2.5">
<Link href={`/u/${u.id}`} className="flex items-center gap-2.5 min-w-0 group">
<Link href={userPath(urlStyle, u.id)} className="flex items-center gap-2.5 min-w-0 group">
<Avatar name={u.nickname || u.username} src={u.avatar || undefined} size={30} />
<span className="min-w-0">
<span