update: replace table component
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
import { type Workspace, type WorkspaceMember } from "../../services/api";
|
||||
import Icon from "../../components/common/Icon";
|
||||
|
||||
export function ProjectMembersDrawer({
|
||||
open,
|
||||
selectedProject,
|
||||
members,
|
||||
membersLoading,
|
||||
canManage,
|
||||
onClose,
|
||||
onAddMembers,
|
||||
onRemoveMember,
|
||||
onNotify,
|
||||
}: {
|
||||
open: boolean;
|
||||
selectedProject: Workspace | null;
|
||||
members: WorkspaceMember[];
|
||||
membersLoading: boolean;
|
||||
canManage: boolean;
|
||||
onClose: () => void;
|
||||
onAddMembers: () => void;
|
||||
onRemoveMember: (userId: string) => void;
|
||||
onNotify: (notice: { tone: "success" | "error" | "info"; message: string }) => void;
|
||||
}) {
|
||||
if (!open || !selectedProject) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="drawer-overlay" onClick={() => onClose()} style={{
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: "rgba(0,0,0,0.3)",
|
||||
zIndex: 99,
|
||||
}} />
|
||||
<aside className="drawer" style={{
|
||||
position: "fixed",
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
width: 480,
|
||||
backgroundColor: "#fff",
|
||||
boxShadow: "-2px 0 8px rgba(0,0,0,0.1)",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
zIndex: 100,
|
||||
}}>
|
||||
<div className="drawer__header" style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
padding: "16px 20px",
|
||||
borderBottom: "1px solid #e8e8e8",
|
||||
}}>
|
||||
<div>
|
||||
<span className="modal__eyebrow" style={{ fontSize: 12, color: "#666" }}>MEMBERS</span>
|
||||
<h3 style={{ margin: 0, fontSize: 18 }}>项目成员</h3>
|
||||
<p style={{ margin: "4px 0 0", fontSize: 13, color: "#888" }}>{selectedProject.workspace_name}</p>
|
||||
</div>
|
||||
<button className="icon-button" type="button" onClick={() => onClose()}>
|
||||
<Icon name="close" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
padding: "12px 20px",
|
||||
borderBottom: "1px solid #f0f0f0",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}>
|
||||
<span style={{ fontSize: 14, color: "#666" }}>
|
||||
共 {members.length} 名成员
|
||||
</span>
|
||||
<button
|
||||
className="primary-button"
|
||||
type="button"
|
||||
onClick={() => onAddMembers()}
|
||||
style={{ fontSize: 13, padding: "6px 12px" }}
|
||||
>
|
||||
<Icon name="plus" size={14} /> 添加成员
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div style={{ flex: 1, overflow: "auto", padding: "12px 20px" }}>
|
||||
{membersLoading ? (
|
||||
<p style={{ textAlign: "center", color: "#999", padding: "40px 0" }}>加载中…</p>
|
||||
) : members.length === 0 ? (
|
||||
<p style={{ textAlign: "center", color: "#999", padding: "40px 0" }}>暂无成员</p>
|
||||
) : (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
|
||||
{members.map((member) => {
|
||||
const isAdmin = member.role_code === "admin";
|
||||
return (
|
||||
<div
|
||||
key={member.user_id}
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
padding: "6px",
|
||||
border: "1px solid #e8e8e8",
|
||||
borderRadius: 6,
|
||||
backgroundColor: "#fafafa",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="avatar"
|
||||
style={{
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: "50%",
|
||||
backgroundColor: "#1890ff",
|
||||
color: "#fff",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
fontSize: 14,
|
||||
fontWeight: 600,
|
||||
marginRight: 10,
|
||||
}}
|
||||
>
|
||||
{member.display_name.slice(0, 1)}
|
||||
</div>
|
||||
<div style={{ flex: 1, minWidth: 0 }}>
|
||||
<div style={{ fontWeight: 500, marginBottom: 2, fontSize: 13 }}>{member.display_name}</div>
|
||||
<div style={{ fontSize: 11, color: "#888" }}>{member.username}</div>
|
||||
</div>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 6 }}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onRemoveMember(member.user_id)}
|
||||
style={{
|
||||
padding: "3px 8px",
|
||||
fontSize: 11,
|
||||
color: isAdmin ? "#999" : "#ff4d4f",
|
||||
border: "1px solid " + (isAdmin ? "#ddd" : "#ff4d4f"),
|
||||
borderRadius: 4,
|
||||
backgroundColor: "#fff",
|
||||
cursor: isAdmin ? "not-allowed" : canManage ? "pointer" : "not-allowed",
|
||||
}}
|
||||
disabled={!canManage || isAdmin}
|
||||
title={isAdmin ? "管理员不能被移除" : canManage ? "移除成员" : "无权限"}
|
||||
>
|
||||
移除
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</aside>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user