配置Vite代理、API请求封装、JWT认证上下文、登录页面、路由鉴权
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import { get, post, getList } from './request'
|
||||
|
||||
export interface LoginParams { username: string; password: string }
|
||||
export interface LoginResult { token: string; user_id: number; tenant_id: number; nickname: string; role: string }
|
||||
|
||||
export interface Session {
|
||||
id: number; tenant_id: number; channel_id: number; customer_id: number; agent_id: number | null
|
||||
status: string; priority: string; satisfaction_score: number | null; created_at: string; ended_at: string | null
|
||||
}
|
||||
|
||||
export interface Customer {
|
||||
id: number; tenant_id: number; name: string; phone: string; email: string; tags: string
|
||||
source: string; status: string; conversation_count: number; last_contact_at: string
|
||||
}
|
||||
|
||||
export interface KnowledgeEntry {
|
||||
id: number; title: string; content: string; status: string; usage_count: number
|
||||
category_id: number; updated_at: string
|
||||
}
|
||||
|
||||
export interface Tenant {
|
||||
id: number; name: string; plan_id: number; seat_count: number; expire_at: string; status: string
|
||||
contact_name: string; contact_phone: string; contact_email: string
|
||||
}
|
||||
|
||||
// Auth
|
||||
export const login = (params: LoginParams) => post<LoginResult>('/login', params)
|
||||
|
||||
// Sessions
|
||||
export const getSessions = (params?: { status?: string; priority?: string; page?: number }) => {
|
||||
const search = new URLSearchParams()
|
||||
if (params?.status) search.set('status', params.status)
|
||||
if (params?.priority) search.set('priority', params.priority)
|
||||
if (params?.page) search.set('page', String(params.page))
|
||||
return getList<Session>(`/sessions?${search}`)
|
||||
}
|
||||
export const getSession = (id: number) => get<{ session: Session; messages: unknown[] }>(`/sessions/${id}`)
|
||||
export const assignSession = (id: number, agentId: number) => post(`/sessions/${id}/assign`, { agent_id: agentId })
|
||||
export const endSession = (id: number, reason: string) => post(`/sessions/${id}/end?reason=${reason}`, {})
|
||||
|
||||
// Customers
|
||||
export const getCustomers = (params?: { search?: string; status?: string; page?: number }) => {
|
||||
const search = new URLSearchParams()
|
||||
if (params?.search) search.set('search', params.search)
|
||||
if (params?.status) search.set('status', params.status)
|
||||
if (params?.page) search.set('page', String(params.page || 1))
|
||||
return getList<Customer>(`/customers?${search}`)
|
||||
}
|
||||
|
||||
// Knowledge
|
||||
export const getKnowledgeCategories = () => get<unknown[]>('/knowledge/categories')
|
||||
export const getKnowledgeEntries = (params?: { category_id?: string; search?: string; page?: number }) => {
|
||||
const search = new URLSearchParams()
|
||||
if (params?.category_id) search.set('category_id', params.category_id)
|
||||
if (params?.search) search.set('search', params.search)
|
||||
if (params?.page) search.set('page', String(params.page || 1))
|
||||
return getList<KnowledgeEntry>(`/knowledge/entries?${search}`)
|
||||
}
|
||||
|
||||
// Statistics
|
||||
export const getKPIs = () => get<Record<string, number>>('/statistics/kpi')
|
||||
export const getSessionTrend = () => get<{ date: string; count: number }[]>('/statistics/trend')
|
||||
|
||||
// Admin
|
||||
export const getTenants = (params?: { search?: string; status?: string; page?: number }) => {
|
||||
const search = new URLSearchParams()
|
||||
if (params?.search) search.set('search', params.search)
|
||||
if (params?.status) search.set('status', params.status)
|
||||
if (params?.page) search.set('page', String(params.page || 1))
|
||||
return getList<Tenant>(`/admin/tenants?${search}`)
|
||||
}
|
||||
export const getAdminStats = () => get('/admin/stats')
|
||||
@@ -0,0 +1,46 @@
|
||||
const BASE = '/api'
|
||||
|
||||
let token = ''
|
||||
|
||||
export function setToken(t: string) { token = t }
|
||||
export function getToken() { return token }
|
||||
|
||||
interface Response<T = unknown> {
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
}
|
||||
|
||||
interface ListResponse<T = unknown> {
|
||||
code: number
|
||||
message: string
|
||||
list: T[]
|
||||
total: number
|
||||
page: number
|
||||
pageSize: number
|
||||
}
|
||||
|
||||
async function request<T>(url: string, options: RequestInit = {}): Promise<T> {
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
...((options.headers as Record<string, string>) || {}),
|
||||
}
|
||||
if (token) headers['Authorization'] = `Bearer ${token}`
|
||||
|
||||
const res = await fetch(`${BASE}${url}`, { ...options, headers })
|
||||
const json = await res.json()
|
||||
|
||||
if (json.code !== 0) {
|
||||
const err = new Error(json.message || '请求失败') as Error & { code: number }
|
||||
err.code = json.code
|
||||
throw err
|
||||
}
|
||||
|
||||
return json
|
||||
}
|
||||
|
||||
export const get = <T>(url: string) => request<Response<T>>(url)
|
||||
export const post = <T>(url: string, data: unknown) => request<Response<T>>(url, { method: 'POST', body: JSON.stringify(data) })
|
||||
export const put = <T>(url: string, data: unknown) => request<Response<T>>(url, { method: 'PUT', body: JSON.stringify(data) })
|
||||
export const del = <T>(url: string) => request<Response<T>>(url, { method: 'DELETE' })
|
||||
export const getList = <T>(url: string) => request<ListResponse<T>>(url)
|
||||
Reference in New Issue
Block a user