OnlineAgentsList.tsx 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. "use client";
  2. import Image from "next/image";
  3. import { getAvatarUrl } from "@/utils/avatar";
  4. export interface OnlineAgent {
  5. id: number;
  6. nickname: string;
  7. avatar_url: string;
  8. }
  9. interface OnlineAgentsListProps {
  10. agents: OnlineAgent[];
  11. onAgentClick?: (agent: OnlineAgent) => void;
  12. }
  13. /**
  14. * 在线客服列表组件
  15. * 显示在线客服的头像和昵称
  16. */
  17. export function OnlineAgentsList({
  18. agents,
  19. onAgentClick,
  20. }: OnlineAgentsListProps) {
  21. if (agents.length === 0) {
  22. return (
  23. <div className="text-sm text-muted-foreground text-center py-4">
  24. 暂无在线客服
  25. </div>
  26. );
  27. }
  28. return (
  29. <div className="space-y-3">
  30. <div className="text-sm font-semibold text-foreground mb-3 text-center flex items-center justify-center gap-2">
  31. <div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
  32. <span>在线</span>
  33. </div>
  34. <div className="flex flex-wrap gap-3 justify-center">
  35. {agents.map((agent) => (
  36. <button
  37. key={agent.id}
  38. onClick={() => onAgentClick?.(agent)}
  39. className="flex flex-col items-center gap-1.5 px-2 py-1 rounded-lg hover:bg-primary/5 transition-all cursor-pointer group"
  40. title={agent.nickname}
  41. >
  42. <div className="relative w-12 h-12 rounded-full overflow-hidden bg-gradient-to-br from-primary/20 to-primary/5 border-2 border-primary/30 group-hover:border-primary/60 transition-all">
  43. {getAvatarUrl(agent.avatar_url) ? (
  44. <Image
  45. src={getAvatarUrl(agent.avatar_url)!}
  46. alt={agent.nickname}
  47. fill
  48. // 头像通常来自后端动态上传路径(/uploads/...),使用 next/image 优化在不同部署形态下容易踩坑
  49. // 这里直接输出 <img> 行为,交给浏览器请求同域 /uploads(由 Nginx 反代到后端)
  50. unoptimized
  51. className="object-cover"
  52. />
  53. ) : (
  54. <div className="w-full h-full flex items-center justify-center bg-gradient-to-br from-primary/20 to-primary/10 text-primary text-base font-semibold">
  55. {agent.nickname.charAt(0).toUpperCase()}
  56. </div>
  57. )}
  58. </div>
  59. <span className="text-xs font-medium text-muted-foreground group-hover:text-foreground transition-colors truncate max-w-[72px]">
  60. {agent.nickname}
  61. </span>
  62. </button>
  63. ))}
  64. </div>
  65. <p className="text-sm font-medium text-muted-foreground text-center pt-1">
  66. 有疑问吗?联系我们!
  67. </p>
  68. </div>
  69. );
  70. }