feat(history): establish Telegram SaaS platform foundation
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { http } from './client'
|
||||
import type { AiAnalysis, AiReplySuggestion, AiTextActionPayload, InterpretLine, TranslatePayload, TranslateResult } from '@/types'
|
||||
import type { AiAnalysis, AiReplySuggestion, AiTextActionPayload, TranslatePayload, TranslateResult } from '@/types'
|
||||
|
||||
/** POST /api/ai/translate */
|
||||
export function translate(payload: TranslatePayload) {
|
||||
@@ -21,12 +21,11 @@ export function summarizeConversation(conversationId: string) {
|
||||
return http.post<{ summary: string }>('/api/ai/summarize', { conversationId })
|
||||
}
|
||||
|
||||
/** POST /api/ai/interpretation */
|
||||
export function nextInterpretLine(index: number) {
|
||||
return http.post<InterpretLine>('/api/ai/interpretation', { index })
|
||||
}
|
||||
|
||||
/** POST /api/ai/text-action(润色/缩写/扩写/语气/翻译) */
|
||||
export function textAction(payload: AiTextActionPayload) {
|
||||
return http.post<{ result: string }>('/api/ai/text-action', payload)
|
||||
}
|
||||
|
||||
export function recordAiAdoption(conversationId: string, content: string, suggestionId = '') {
|
||||
return http.post<{ id: string }>('/api/ai/adoptions', { conversationId, content, suggestionId })
|
||||
}
|
||||
|
||||
@@ -16,7 +16,36 @@ export function me() {
|
||||
return http.get<{ user: AuthSession['user']; tenant: AuthSession['tenant'] }>('/api/auth/me')
|
||||
}
|
||||
|
||||
/** 发送验证码(演示:固定可收到 6 位码) */
|
||||
export function sendCode(account: string) {
|
||||
return http.post<{ sent: boolean }>('/api/auth/send-code', { account }).catch(() => ({ sent: true }))
|
||||
export function getWebSocketTicket() {
|
||||
return http.post<{ ticket: string; expiresAt: string }>('/api/auth/ws-ticket', {})
|
||||
}
|
||||
|
||||
export function changePassword(payload: { currentPassword: string; newPassword: string }) {
|
||||
return http.post<{ success: boolean; loginRequired: boolean }>('/api/auth/change-password', payload)
|
||||
}
|
||||
|
||||
export function revokeAllSessions() {
|
||||
return http.post<{ success: boolean }>('/api/auth/logout-all', {})
|
||||
}
|
||||
|
||||
export interface ApiKeyRecord {
|
||||
id: string
|
||||
name: string
|
||||
prefix: string
|
||||
role: string
|
||||
createdAt: string
|
||||
revoked: boolean
|
||||
key?: string
|
||||
}
|
||||
|
||||
export function getApiKeys() {
|
||||
return http.get<ApiKeyRecord[]>('/api/api-keys')
|
||||
}
|
||||
|
||||
export function createApiKey(name: string, role = 'service') {
|
||||
return http.post<ApiKeyRecord>('/api/api-keys', { name, role })
|
||||
}
|
||||
|
||||
export function revokeApiKey(id: string) {
|
||||
return http.del<{ success: boolean }>(`/api/api-keys/${id}`)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,22 @@ export function connectChannel(payload: {
|
||||
return http.post<ChannelConnection>('/api/channels/connect', payload)
|
||||
}
|
||||
|
||||
export function startTelegramLogin(phone: string) {
|
||||
return http.post<ChannelConnection>('/api/channels/telegram/start', { phone })
|
||||
}
|
||||
|
||||
export function submitTelegramCode(channelId: string, code: string) {
|
||||
return http.post<{ status: string; channel: ChannelConnection }>(`/api/channels/telegram/${channelId}/code`, { code })
|
||||
}
|
||||
|
||||
export function submitTelegramPassword(channelId: string, password: string) {
|
||||
return http.post<{ status: string; channel: ChannelConnection }>(`/api/channels/telegram/${channelId}/password`, { password })
|
||||
}
|
||||
|
||||
export function syncTelegramChannel(channelId: string) {
|
||||
return http.post<{ chats: number; messages: number }>(`/api/channels/${channelId}/sync`)
|
||||
}
|
||||
|
||||
/** POST /api/channels/test */
|
||||
export function testChannel(id: string) {
|
||||
return http.post<{ success: boolean; latencyMs: number; message: string }>('/api/channels/test', { id })
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
/**
|
||||
* 统一 API 客户端
|
||||
* - VITE_USE_MOCK=true :走内置 Mock 路由(本地模拟数据,含模拟网络延迟)
|
||||
* - VITE_USE_MOCK=false :请求真实后端(VITE_API_BASE_URL),自动携带 Bearer Token
|
||||
*/
|
||||
/** 灵犀跨境统一 API 客户端:所有请求均访问真实后端。 */
|
||||
import { env } from '@/config/env'
|
||||
import { mockRequest } from '@/services/mock'
|
||||
|
||||
export class ApiError extends Error {
|
||||
code: number
|
||||
@@ -29,10 +24,6 @@ export function setTokenGetter(fn: () => string | null) {
|
||||
export async function api<T = unknown>(path: string, options: RequestOptions = {}): Promise<T> {
|
||||
const method = options.method ?? 'GET'
|
||||
|
||||
if (env.useMock) {
|
||||
return mockRequest<T>(method, path, options.query ?? {}, options.body)
|
||||
}
|
||||
|
||||
const base = env.apiBaseUrl.replace(/\/$/, '')
|
||||
const url = new URL(`${base}${path}`, window.location.origin)
|
||||
Object.entries(options.query ?? {}).forEach(([k, v]) => {
|
||||
@@ -54,7 +45,9 @@ export async function api<T = unknown>(path: string, options: RequestOptions = {
|
||||
}
|
||||
if (!res.ok) {
|
||||
const text = await res.text().catch(() => '')
|
||||
throw new ApiError(res.status, text || `请求失败(${res.status})`)
|
||||
let message = text
|
||||
try { message = (JSON.parse(text) as { message?: string }).message ?? text } catch { /* 保留原始响应 */ }
|
||||
throw new ApiError(res.status, message || `请求失败(${res.status})`)
|
||||
}
|
||||
const json = (await res.json().catch(() => null)) as { code?: number; message?: string; data?: T } | T | null
|
||||
// 兼容 {code,message,data} 与直接返回数据两种后端风格
|
||||
|
||||
@@ -25,11 +25,39 @@ export function getMessages(id: string) {
|
||||
return http.get<Message[]>(`/api/conversations/${id}/messages`)
|
||||
}
|
||||
|
||||
export function updateMessage(id: string, messageId: string, payload: { isImportant?: boolean; internalNote?: string }) {
|
||||
return http.patch<Message>(`/api/conversations/${id}/messages/${messageId}`, payload)
|
||||
}
|
||||
|
||||
export function markConversationRead(id: string, messageIds?: string[]) {
|
||||
return http.post<Conversation>(`/api/conversations/${id}/read`, { messageIds })
|
||||
}
|
||||
|
||||
export function getMessageAttachment(id: string, messageId: string) {
|
||||
return http.get<{ dataUrl: string; mimeType: string; name: string }>(
|
||||
`/api/conversations/${id}/messages/${messageId}/attachment`,
|
||||
)
|
||||
}
|
||||
|
||||
/** POST /api/conversations/:id/messages */
|
||||
export function sendMessage(id: string, payload: SendMessagePayload & { translatedText?: string }) {
|
||||
export function sendMessage(id: string, payload: SendMessagePayload & { translatedText?: string; autoTranslate?: boolean }) {
|
||||
return http.post<Message>(`/api/conversations/${id}/messages`, payload)
|
||||
}
|
||||
|
||||
export function sendMedia(
|
||||
id: string,
|
||||
payload: { name: string; mimeType: string; base64: string; kind: 'document' | 'photo' | 'audio' | 'voice' | 'sticker' },
|
||||
) {
|
||||
return http.post<unknown>(`/api/conversations/${id}/media`, payload)
|
||||
}
|
||||
|
||||
export function sendAlbum(
|
||||
id: string,
|
||||
files: Array<{ name: string; mimeType: string; base64: string }>,
|
||||
) {
|
||||
return http.post<unknown>(`/api/conversations/${id}/album`, { files })
|
||||
}
|
||||
|
||||
/** PATCH /api/conversations/:id(标记已读/分配/状态) */
|
||||
export function updateConversation(id: string, payload: { assigneeId?: string | null; markRead?: boolean; status?: string }) {
|
||||
return http.patch<Conversation>(`/api/conversations/${id}`, payload)
|
||||
|
||||
@@ -22,7 +22,7 @@ export function deleteKnowledge(id: string) {
|
||||
}
|
||||
|
||||
/** POST /api/knowledge/upload */
|
||||
export function uploadKnowledgeFiles(files: { name: string; type: string }[]) {
|
||||
export function uploadKnowledgeFiles(files: { name: string; type: string; base64: string }[]) {
|
||||
return http.post<{ items: KnowledgeItem[] }>('/api/knowledge/upload', { files })
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ export function getBilling() {
|
||||
|
||||
/** POST /api/billing/upgrade */
|
||||
export function upgradePlan(planKey: string) {
|
||||
return http.post<BillingInfo>('/api/billing/upgrade', { planKey })
|
||||
return http.post<{ checkoutUrl: string; sessionId: string }>('/api/billing/upgrade', { planKey })
|
||||
}
|
||||
|
||||
/* ===== 设置 ===== */
|
||||
|
||||
Reference in New Issue
Block a user