customerService.ts 2.39 KB
import { service as http } from "@/utils/request";
import { askQuestion, streamAnswer, createChat } from "@/api/chat";
import type { AxiosPromise } from "axios";

const CS_CHAT_KEY = "cs_chat_id";

function getToken(): string {
  return localStorage.getItem("auth_token") || "";
}

function authHeaders(): { Authorization?: string } {
  const t = getToken();
  return t ? { Authorization: `Bearer ${t}` } : {};
}

/** 获取或创建客服专用会话 ID */
export async function getOrCreateCsChatId(): Promise<number> {
  const cached = localStorage.getItem(CS_CHAT_KEY);
  if (cached) return parseInt(cached, 10);

  const res = await createChat({ title: "智能客服" });
  const chatId = (res.data as any)?.data?.id ?? (res.data as any)?.id;
  if (!chatId) throw new Error("创建客服会话失败");
  localStorage.setItem(CS_CHAT_KEY, String(chatId));
  return chatId;
}

/** 重置客服会话(清除缓存,下次会新建) */
export function resetCsChat(): void {
  localStorage.removeItem(CS_CHAT_KEY);
}

interface CsAskResult {
  chatId: number;
  questionId: string;
}

/** 发送客服问题,返回 chatId + questionId 用于后续流式订阅 */
export async function csAsk(
  content: string,
  chatId?: number,
): Promise<CsAskResult> {
  const resolvedChatId = chatId ?? (await getOrCreateCsChatId());

  const res = await askQuestion({
    chatId: resolvedChatId,
    questionContent: content,
  });

  const data = (res.data as any)?.data ?? res.data;
  const questionId: string = data?.questionId ?? data?.externalQuestionId ?? "";

  return { chatId: resolvedChatId, questionId };
}

interface CsStreamOptions {
  chatId: number;
  questionId: string;
  onChunk: (text: string) => void;
  onDone: () => void;
  onError: (err: any) => void;
  signal?: AbortSignal;
}

/** 订阅客服流式回答 */
export function csStream({
  chatId,
  questionId,
  onChunk,
  onDone,
  onError,
  signal,
}: CsStreamOptions): { close: () => void } {
  return streamAnswer({
    chatId,
    questionId,
    onMessage: (payload) => {
      if (typeof payload === "string") {
        onChunk(payload);
      } else if (payload && typeof payload === "object") {
        const p = payload as any;
        const text =
          p?.choices?.[0]?.delta?.content ??
          p?.delta?.content ??
          p?.content ??
          "";
        if (text) onChunk(text);
      }
    },
    onEnd: onDone,
    onError,
    signal,
  });
}