conversationApi.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import { apiUrl, getAgentHeaders } from "@/lib/config";
  2. import {
  3. ConversationDetail,
  4. ConversationSummary,
  5. } from "../types";
  6. export type ConversationListType = "visitor" | "internal";
  7. export async function fetchConversations(
  8. userId?: number,
  9. opts?: { type?: ConversationListType }
  10. ): Promise<ConversationSummary[]> {
  11. const params = new URLSearchParams();
  12. if (userId) params.set("user_id", String(userId));
  13. if (opts?.type) params.set("type", opts.type);
  14. const url = `${apiUrl("/conversations")}?${params.toString()}`;
  15. const res = await fetch(url, { cache: "no-store", headers: getAgentHeaders() });
  16. if (!res.ok) {
  17. throw new Error("获取对话列表失败");
  18. }
  19. const data = await res.json();
  20. if (!Array.isArray(data)) {
  21. return [];
  22. }
  23. return data.map((item) => ({
  24. ...item,
  25. unread_count: item.unread_count ?? 0,
  26. has_participated: item.has_participated ?? false,
  27. }));
  28. }
  29. /** 创建一条内部对话(知识库测试),返回新对话 ID */
  30. export async function initInternalConversation(userId: number): Promise<{ conversation_id: number }> {
  31. const res = await fetch(`${apiUrl("/conversations/internal")}?user_id=${userId}`, {
  32. method: "POST",
  33. headers: { "Content-Type": "application/json", ...getAgentHeaders() },
  34. });
  35. if (!res.ok) {
  36. const err = await res.json().catch(() => ({}));
  37. throw new Error((err as { error?: string }).error || "创建内部对话失败");
  38. }
  39. const data = await res.json();
  40. return { conversation_id: data.conversation_id };
  41. }
  42. export async function searchConversations(
  43. query: string,
  44. userId?: number
  45. ): Promise<ConversationSummary[]> {
  46. const url = userId
  47. ? `${apiUrl("/conversations/search")}?q=${encodeURIComponent(query)}&user_id=${userId}`
  48. : `${apiUrl("/conversations/search")}?q=${encodeURIComponent(query)}`;
  49. const res = await fetch(url, {
  50. cache: "no-store",
  51. headers: getAgentHeaders(),
  52. });
  53. if (!res.ok) {
  54. throw new Error("搜索对话失败");
  55. }
  56. const data = await res.json();
  57. if (!Array.isArray(data)) {
  58. return [];
  59. }
  60. return data.map((item) => ({
  61. ...item,
  62. unread_count: item.unread_count ?? 0,
  63. has_participated: item.has_participated ?? false,
  64. }));
  65. }
  66. export async function fetchConversationDetail(
  67. conversationId: number,
  68. userId?: number
  69. ): Promise<ConversationDetail | null> {
  70. const url = userId
  71. ? `${apiUrl(`/conversations/${conversationId}`)}?user_id=${userId}`
  72. : apiUrl(`/conversations/${conversationId}`);
  73. const res = await fetch(url, { cache: "no-store", headers: getAgentHeaders() });
  74. if (!res.ok) {
  75. return null;
  76. }
  77. const data = await res.json();
  78. return {
  79. ...data,
  80. unread_count: data.unread_count ?? 0,
  81. };
  82. }
  83. export interface UpdateConversationContactPayload {
  84. email?: string;
  85. phone?: string;
  86. notes?: string;
  87. }
  88. export interface UpdateConversationContactResult {
  89. email: string;
  90. phone: string;
  91. notes: string;
  92. }
  93. export async function updateConversationContact(
  94. conversationId: number,
  95. payload: UpdateConversationContactPayload
  96. ): Promise<UpdateConversationContactResult> {
  97. const res = await fetch(
  98. apiUrl(`/conversations/${conversationId}/contact`),
  99. {
  100. method: "PUT",
  101. headers: { "Content-Type": "application/json", ...getAgentHeaders() },
  102. body: JSON.stringify(payload),
  103. }
  104. );
  105. if (!res.ok) {
  106. throw new Error("更新访客联系信息失败");
  107. }
  108. const data = await res.json();
  109. return {
  110. email: data.email ?? "",
  111. phone: data.phone ?? "",
  112. notes: data.notes ?? "",
  113. };
  114. }