fix: 空评论列表 500,并完善撤回审计与角色说明
空切片 JSON 统一为数组;撤回保留正文供站长阅读,成员侧居中提示与重新编辑;头像支持拖放;角色弹窗补全职责说明并汇入封禁。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useCallback, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Check } from "lucide-react";
|
||||
import { apiUpdateProfile, type User } from "@/lib/api";
|
||||
@@ -23,6 +23,34 @@ export default function ProfileForm({ user }: ProfileFormProps) {
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [success, setSuccess] = useState("");
|
||||
const [avatarDragOver, setAvatarDragOver] = useState(false);
|
||||
const [incomingAvatarFile, setIncomingAvatarFile] = useState<File | null>(null);
|
||||
|
||||
const clearIncomingAvatar = useCallback(() => setIncomingAvatarFile(null), []);
|
||||
|
||||
const handleAvatarDragOver = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (e.dataTransfer.types.includes("Files")) setAvatarDragOver(true);
|
||||
};
|
||||
|
||||
const handleAvatarDragLeave = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
// 仅在离开整块卡片时取消高亮(避免子元素冒泡闪烁)
|
||||
const related = e.relatedTarget as Node | null;
|
||||
if (related && e.currentTarget.contains(related)) return;
|
||||
setAvatarDragOver(false);
|
||||
};
|
||||
|
||||
const handleAvatarDrop = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setAvatarDragOver(false);
|
||||
const file = e.dataTransfer.files?.[0];
|
||||
if (!file) return;
|
||||
setIncomingAvatarFile(file);
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
@@ -72,20 +100,32 @@ export default function ProfileForm({ user }: ProfileFormProps) {
|
||||
)}
|
||||
{error && <div className="alert-error" role="alert">{error}</div>}
|
||||
|
||||
{/* 头像:点击上传/裁剪,或从历史图片中选择 */}
|
||||
{/* 头像:点击上传/裁剪,或拖放图片到本区域 */}
|
||||
<div
|
||||
className="flex items-center gap-4 p-4 rounded-xl"
|
||||
style={{ background: "var(--panel-2)", border: "1px solid var(--line)" }}
|
||||
className="flex items-center gap-4 p-4 rounded-xl transition-colors"
|
||||
style={{
|
||||
background: avatarDragOver
|
||||
? "color-mix(in srgb, var(--accent) 12%, var(--panel-2))"
|
||||
: "var(--panel-2)",
|
||||
border: `1px solid ${avatarDragOver ? "var(--accent)" : "var(--line)"}`,
|
||||
}}
|
||||
onDragOver={handleAvatarDragOver}
|
||||
onDragLeave={handleAvatarDragLeave}
|
||||
onDrop={handleAvatarDrop}
|
||||
>
|
||||
<AvatarPicker
|
||||
name={nickname || user.username}
|
||||
src={user.avatar || ""}
|
||||
size={56}
|
||||
incomingFile={incomingAvatarFile}
|
||||
onIncomingConsumed={clearIncomingAvatar}
|
||||
/>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-[13.5px] font-bold" style={{ color: "var(--ink)" }}>头像</p>
|
||||
<p className="text-[12px] mt-1" style={{ color: "var(--ink-3)" }}>
|
||||
点击头像上传新图片,支持拖动裁剪;统一转为 WebP,裁剪后不超过 2MB
|
||||
{avatarDragOver
|
||||
? "松开即可上传并裁剪"
|
||||
: "点击头像或拖放图片到此处;支持拖动裁剪,统一转为 WebP,裁剪后不超过 2MB"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user