ConversationSidebar.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. "use client";
  2. import { ConversationSummary } from "@/features/agent/types";
  3. import { ConversationHeader, type ConversationFilter } from "./ConversationHeader";
  4. import { ConversationSearch } from "./ConversationSearch";
  5. import { ConversationList } from "./ConversationList";
  6. import { Button } from "@/components/ui/button";
  7. import { Plus } from "lucide-react";
  8. type ConversationStatus = "open" | "closed";
  9. interface ConversationSidebarProps {
  10. conversations: ConversationSummary[];
  11. selectedConversationId: number | null;
  12. searchQuery: string;
  13. onSearchChange: (value: string) => void;
  14. onSelectConversation: (id: number) => void;
  15. filter: ConversationFilter;
  16. onFilterChange: (filter: ConversationFilter) => void;
  17. status?: ConversationStatus;
  18. onStatusChange?: (status: ConversationStatus) => void;
  19. /** 内部对话(知识库测试)模式:显示「新建内部对话」按钮,隐藏筛选 */
  20. mode?: "visitor" | "internal";
  21. onNewClick?: () => void;
  22. }
  23. export function ConversationSidebar({
  24. conversations,
  25. selectedConversationId,
  26. searchQuery,
  27. onSearchChange,
  28. onSelectConversation,
  29. filter,
  30. onFilterChange,
  31. status = "open",
  32. onStatusChange,
  33. mode = "visitor",
  34. onNewClick,
  35. }: ConversationSidebarProps) {
  36. return (
  37. <div className="w-80 min-w-0 flex-1 flex flex-col bg-white border-r border-gray-200 min-h-0 overflow-hidden">
  38. {mode === "internal" ? (
  39. <div className="h-14 flex items-center justify-between px-3 border-b border-border bg-background flex-shrink-0">
  40. <span className="text-sm font-medium text-foreground truncate">知识库测试</span>
  41. {onNewClick && (
  42. <Button size="sm" variant="outline" onClick={onNewClick} className="flex-shrink-0 gap-1">
  43. <Plus className="w-4 h-4" />
  44. 新建
  45. </Button>
  46. )}
  47. </div>
  48. ) : (
  49. <div className="flex flex-col">
  50. <ConversationHeader filter={filter} onFilterChange={onFilterChange} />
  51. <div className="px-3 pb-2 flex items-center gap-2">
  52. <button
  53. type="button"
  54. className={`px-3 py-1.5 rounded-md text-xs border transition ${
  55. status === "open"
  56. ? "bg-green-600 text-white border-green-600"
  57. : "bg-background text-muted-foreground border-border hover:text-foreground"
  58. }`}
  59. onClick={() => onStatusChange?.("open")}
  60. >
  61. 进行中
  62. </button>
  63. <button
  64. type="button"
  65. className={`px-3 py-1.5 rounded-md text-xs border transition ${
  66. status === "closed"
  67. ? "bg-green-600 text-white border-green-600"
  68. : "bg-background text-muted-foreground border-border hover:text-foreground"
  69. }`}
  70. onClick={() => onStatusChange?.("closed")}
  71. >
  72. 历史
  73. </button>
  74. </div>
  75. </div>
  76. )}
  77. <div className="flex-shrink-0 px-2 min-w-0">
  78. <ConversationSearch value={searchQuery} onChange={onSearchChange} />
  79. </div>
  80. <ConversationList
  81. conversations={conversations}
  82. selectedConversationId={selectedConversationId}
  83. onSelect={onSelectConversation}
  84. searchQuery={searchQuery}
  85. />
  86. </div>
  87. );
  88. }