feat: 完成头像上传、站点主题配置与UI优化

- 新增附件模型与上传服务,拆分头像上传/管理逻辑
- 重构用户资料接口,移除直接修改头像字段,改用专用上传接口
- 添加站点公开设置API与管理员外观配置页
- 全局替换hover背景为accent-soft,优化交互一致性
- 完善头像组件,支持图片加载失败回退与src更新重置
- 新增用户状态事件总线,解决同页头像更新不及时问题
- 调整依赖包顺序与CI依赖版本
- 重构板块列表接口,新增帖子计数
- 迁移账号设置到用户主页tab,合并重复代码
This commit is contained in:
2026-09-15 01:06:12 +08:00
parent f58b2af993
commit 24c6dea38c
48 changed files with 2513 additions and 432 deletions

View File

@@ -1,3 +1,7 @@
"use client";
import { useEffect, useState } from "react";
// 柔和多色头像:按用户名确定性取色,圆形软底,浅/暗主题在 globals.css 各自配色
function hash(s: string) {
let h = 0;
@@ -18,15 +22,26 @@ export default function Avatar({
}) {
const idx = hash(name || "?") % 8;
const initial = (name || "?").trim().charAt(0).toUpperCase();
// 图片 404(如附件已被彻底删除)时回退到字母头像,不显示裂图
const [imgFailed, setImgFailed] = useState(false);
// 切换到新的图片地址时重置失败状态
useEffect(() => setImgFailed(false), [src]);
const showImg = !!src && !imgFailed;
return (
<span
className={`inline-flex items-center justify-center shrink-0 select-none font-bold rounded-full overflow-hidden av-${idx} ${className}`}
style={{ width: size, height: size, fontSize: size * 0.42 }}
aria-hidden="true"
>
{src ? (
{showImg ? (
// eslint-disable-next-line @next/next/no-img-element
<img src={src} alt="" className="w-full h-full object-cover" />
<img
src={src}
alt=""
className="w-full h-full object-cover"
onError={() => setImgFailed(true)}
/>
) : (
initial
)}