2026-08-01 16:27:22 +08:00
|
|
|
// Typed endpoint wrappers for the M5b browse experience.
|
|
|
|
|
//
|
|
|
|
|
// Mirrors the FastAPI routes in yunke-server/app/api/routers/. Each wrapper
|
|
|
|
|
// drops `undefined`/empty params so the query string only carries set filters
|
|
|
|
|
// (the backend treats missing as "no filter").
|
|
|
|
|
import { getJson } from './client'
|
|
|
|
|
import type {
|
2026-08-01 16:38:47 +08:00
|
|
|
CallChannel,
|
2026-08-01 16:27:22 +08:00
|
|
|
Channel,
|
|
|
|
|
Customer,
|
|
|
|
|
Department,
|
2026-08-01 16:38:47 +08:00
|
|
|
Group,
|
|
|
|
|
GroupMember,
|
2026-08-01 16:27:22 +08:00
|
|
|
Message,
|
|
|
|
|
Page,
|
2026-08-01 16:38:47 +08:00
|
|
|
PhoneCall,
|
|
|
|
|
Sms,
|
2026-08-01 16:27:22 +08:00
|
|
|
Staff,
|
2026-08-01 16:38:47 +08:00
|
|
|
SyncRun,
|
|
|
|
|
SyncState,
|
|
|
|
|
SyncStatus,
|
2026-08-01 16:27:22 +08:00
|
|
|
} from './types'
|
|
|
|
|
|
|
|
|
|
/** Drop entries whose value is `undefined`, `null`, or `''`. */
|
|
|
|
|
function clean(params: Record<string, unknown>): Record<string, unknown> {
|
|
|
|
|
const out: Record<string, unknown> = {}
|
|
|
|
|
for (const [k, v] of Object.entries(params)) {
|
|
|
|
|
if (v === undefined || v === null || v === '') continue
|
|
|
|
|
out[k] = v
|
|
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CustomerQuery {
|
|
|
|
|
channel?: Channel | 'all'
|
|
|
|
|
page?: number
|
|
|
|
|
page_size?: number
|
|
|
|
|
owner_account_id?: string
|
|
|
|
|
department_id?: string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getCustomers(query: CustomerQuery = {}): Promise<Page<Customer>> {
|
|
|
|
|
return getJson<Page<Customer>>(
|
|
|
|
|
'/customers',
|
|
|
|
|
clean({
|
|
|
|
|
page: query.page ?? 1,
|
|
|
|
|
page_size: query.page_size ?? 20,
|
|
|
|
|
channel: query.channel === 'all' ? undefined : query.channel,
|
|
|
|
|
owner_account_id: query.owner_account_id,
|
|
|
|
|
department_id: query.department_id,
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface MessageQuery {
|
|
|
|
|
channel?: Channel
|
|
|
|
|
owner_account_id: string
|
|
|
|
|
talker_id?: string
|
|
|
|
|
room_id?: string
|
|
|
|
|
start?: number
|
|
|
|
|
end?: number
|
|
|
|
|
page?: number
|
|
|
|
|
page_size?: number
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getMessages(query: MessageQuery): Promise<Page<Message>> {
|
|
|
|
|
return getJson<Page<Message>>(
|
|
|
|
|
'/messages',
|
|
|
|
|
clean({
|
|
|
|
|
channel: query.channel,
|
|
|
|
|
owner_account_id: query.owner_account_id,
|
|
|
|
|
talker_id: query.talker_id,
|
|
|
|
|
room_id: query.room_id,
|
|
|
|
|
start: query.start,
|
|
|
|
|
end: query.end,
|
|
|
|
|
page: query.page ?? 1,
|
|
|
|
|
page_size: query.page_size ?? 50,
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getDepartments(): Promise<Department[]> {
|
|
|
|
|
return getJson<Department[]>('/departments')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface StaffQuery {
|
|
|
|
|
department_id?: string
|
|
|
|
|
is_on_job?: boolean
|
|
|
|
|
page?: number
|
|
|
|
|
page_size?: number
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getStaff(query: StaffQuery = {}): Promise<Page<Staff>> {
|
|
|
|
|
return getJson<Page<Staff>>(
|
|
|
|
|
'/staff',
|
|
|
|
|
clean({
|
|
|
|
|
department_id: query.department_id,
|
|
|
|
|
is_on_job: query.is_on_job,
|
|
|
|
|
page: query.page ?? 1,
|
|
|
|
|
page_size: query.page_size ?? 20,
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-01 16:38:47 +08:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Chat groups
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
export interface GroupQuery {
|
|
|
|
|
channel?: Channel | 'all'
|
|
|
|
|
owner_account_id?: string
|
|
|
|
|
page?: number
|
|
|
|
|
page_size?: number
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getGroups(query: GroupQuery = {}): Promise<Page<Group>> {
|
|
|
|
|
return getJson<Page<Group>>(
|
|
|
|
|
'/groups',
|
|
|
|
|
clean({
|
|
|
|
|
channel: query.channel === 'all' ? undefined : query.channel,
|
|
|
|
|
owner_account_id: query.owner_account_id,
|
|
|
|
|
page: query.page ?? 1,
|
|
|
|
|
page_size: query.page_size ?? 20,
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getGroupMembers(roomId: string): Promise<GroupMember[]> {
|
|
|
|
|
// room_id can contain '@' — axios encodes params, but path segments need
|
|
|
|
|
// explicit encoding so the FastAPI `{room_id}` path param matches.
|
|
|
|
|
return getJson<GroupMember[]>(
|
|
|
|
|
`/groups/${encodeURIComponent(roomId)}/members`,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Phone / voice calls
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
export interface CallQuery {
|
|
|
|
|
/** call-type filter; `'all'` (default) drops the param. */
|
|
|
|
|
channel?: CallChannel | 'all'
|
|
|
|
|
user_id?: string
|
|
|
|
|
/** ms-epoch inclusive window compared against start_call_time. */
|
|
|
|
|
start?: number
|
|
|
|
|
end?: number
|
|
|
|
|
page?: number
|
|
|
|
|
page_size?: number
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getCalls(query: CallQuery = {}): Promise<Page<PhoneCall>> {
|
|
|
|
|
return getJson<Page<PhoneCall>>(
|
|
|
|
|
'/calls',
|
|
|
|
|
clean({
|
|
|
|
|
channel: query.channel === 'all' ? undefined : query.channel,
|
|
|
|
|
user_id: query.user_id,
|
|
|
|
|
start: query.start,
|
|
|
|
|
end: query.end,
|
|
|
|
|
page: query.page ?? 1,
|
|
|
|
|
page_size: query.page_size ?? 20,
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// SMS
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
export interface SmsQuery {
|
|
|
|
|
user_id?: string
|
|
|
|
|
/** ms-epoch inclusive window compared against create_time. */
|
|
|
|
|
start?: number
|
|
|
|
|
end?: number
|
|
|
|
|
page?: number
|
|
|
|
|
page_size?: number
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getSms(query: SmsQuery = {}): Promise<Page<Sms>> {
|
|
|
|
|
return getJson<Page<Sms>>(
|
|
|
|
|
'/sms',
|
|
|
|
|
clean({
|
|
|
|
|
user_id: query.user_id,
|
|
|
|
|
start: query.start,
|
|
|
|
|
end: query.end,
|
|
|
|
|
page: query.page ?? 1,
|
|
|
|
|
page_size: query.page_size ?? 20,
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Sync monitor
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
export function getSyncStatus(): Promise<SyncStatus> {
|
|
|
|
|
return getJson<SyncStatus>('/sync/status')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type {
|
|
|
|
|
CallChannel,
|
|
|
|
|
Channel,
|
|
|
|
|
Customer,
|
|
|
|
|
Department,
|
|
|
|
|
Group,
|
|
|
|
|
GroupMember,
|
|
|
|
|
Message,
|
|
|
|
|
Page,
|
|
|
|
|
PhoneCall,
|
|
|
|
|
Sms,
|
|
|
|
|
Staff,
|
|
|
|
|
SyncRun,
|
|
|
|
|
SyncState,
|
|
|
|
|
SyncStatus,
|
|
|
|
|
}
|