feat(staffchat): 路由+API client+类型+relativeChatTime(还原旧页WIP+占位StaffChat)

- 还原 ChatTimeline.vue/api/index.ts 未提交 WIP(新页自建,旧文件回 HEAD)
- /staff-chat/:ownerId/:tab?/:talkerId? 路由 + 占位 StaffChat.vue(Task 9 替换)
- types: MomentsPost/MomentsList/StaffStatsCounts/StaffStatsDetail +
  ChatSession.pinned + Account.avatar
- api: getMoments/getStaffStatsCounts/getStaffStatsDetail + sessions
  is_del + messages msg_type/q 过滤
- format: relativeChatTime(今天HH:mm/昨天/M月D日/YYYY年M月D日) + 4 例
  vitest spec(全过,vitest 未入 devDependencies,npx 拉取运行)
- tsconfig.app.json exclude __tests__(vitest 未装,保持 vue-tsc 通过)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
浅念
2026-08-25 16:44:47 +08:00
parent 4baa8639ba
commit f2bcac0a4d
7 changed files with 208 additions and 2 deletions
+75 -1
View File
@@ -14,12 +14,15 @@ import type {
Group,
GroupMember,
Message,
MomentsList,
Page,
PhoneCall,
SessionList,
Sms,
Staff,
StaffChatStats,
StaffStatsCounts,
StaffStatsDetail,
SyncRun,
SyncState,
SyncStatus,
@@ -80,6 +83,10 @@ export interface MessageQuery {
owner_account_id?: string
talker_id?: string
room_id?: string
/** 结构化类型过滤(如 red_transfer),对齐云客聊天筛选。 */
msg_type?: string
/** 全文模糊搜索。 */
q?: string
start?: number
end?: number
page?: number
@@ -94,6 +101,8 @@ export function getMessages(query: MessageQuery): Promise<Page<Message>> {
owner_account_id: query.owner_account_id,
talker_id: query.talker_id,
room_id: query.room_id,
msg_type: query.msg_type,
q: query.q,
start: query.start,
end: query.end,
page: query.page ?? 1,
@@ -327,12 +336,74 @@ export function getStaffChatStats(query: StaffChatStatsQuery): Promise<StaffChat
export interface SessionQuery {
owner_account_id: string
channel?: Channel
/** 1 = 只看已删除会话(云客侧标记),缺省 = 全部。 */
is_del?: number
}
export function getSessions(query: SessionQuery): Promise<SessionList> {
return getJson<SessionList>(
'/sessions',
clean({ owner_account_id: query.owner_account_id, channel: query.channel }),
clean({
owner_account_id: query.owner_account_id,
channel: query.channel,
is_del: query.is_del,
}),
)
}
// ---------------------------------------------------------------------------
// 员工聊天窗口 (staff-chat, 对齐云客 wechat-window): 朋友圈 + 风控统计
// ---------------------------------------------------------------------------
export interface MomentsQuery {
wechat_id: string
page?: number
page_size?: number
}
export function getMoments(query: MomentsQuery): Promise<MomentsList> {
return getJson<MomentsList>(
'/moments',
clean({
wechat_id: query.wechat_id,
page: query.page,
page_size: query.page_size,
}),
)
}
export interface StaffStatsQuery {
wechat_id: string
/** 传 kind 走明细模式,缺省返回 7 数字 counts。 */
kind?: string
start?: number
end?: number
}
export function getStaffStatsCounts(
query: Omit<StaffStatsQuery, 'kind'>,
): Promise<StaffStatsCounts> {
return getJson<StaffStatsCounts>(
'/staff-stats',
clean({
wechat_id: query.wechat_id,
start: query.start,
end: query.end,
}),
)
}
export function getStaffStatsDetail(
query: StaffStatsQuery & { kind: string },
): Promise<StaffStatsDetail> {
return getJson<StaffStatsDetail>(
'/staff-stats',
clean({
wechat_id: query.wechat_id,
kind: query.kind,
start: query.start,
end: query.end,
}),
)
}
@@ -396,12 +467,15 @@ export type {
Group,
GroupMember,
Message,
MomentsList,
Page,
PhoneCall,
SessionList,
Sms,
Staff,
StaffChatStats,
StaffStatsCounts,
StaffStatsDetail,
SyncRun,
SyncState,
SyncStatus,
+48
View File
@@ -77,6 +77,7 @@ export interface Account {
channel: Channel
account_id: string
nickname?: string | null
avatar?: string | null
user_id?: string | null
user_name?: string | null
phone?: string | null
@@ -354,6 +355,8 @@ export interface ChatSession {
avatar?: string | null
today_count: number
last_chat_time?: number | null
/** 置顶会话(云客侧标记)。 */
pinned?: boolean
}
export interface SessionList {
@@ -362,3 +365,48 @@ export interface SessionList {
today_start: number
sessions: ChatSession[]
}
// ---------------------------------------------------------------------------
// 员工聊天窗口 (staff-chat, 对齐云客 wechat-window): 朋友圈 + 风控统计
// ---------------------------------------------------------------------------
/** 朋友圈单条动态(镜像 backend /api/moments 行)。 */
export interface MomentsPost {
id: string
wechat_id: string
content?: string | null
type_raw?: string | null
/** ms-epoch */
create_time?: number | null
author_name?: string | null
author_avatar?: string | null
/** 点赞者列表(仅取 name 展示)。 */
praise_json?: { name?: string }[] | null
/** 评论列表(结构随上游,前端按需解释)。 */
comment_json?: unknown[] | null
image_urls?: string[] | null
}
/** GET /api/moments 响应(header 为账号名片,total 为总数,items 分页)。 */
export interface MomentsList {
header: { nickname: string | null; avatar: string | null; alias: string | null }
total: number
items: MomentsPost[]
}
/** 员工风控统计 7 数字(GET /api/staff-stats 无 kind 时)。 */
export interface StaffStatsCounts {
new_customers: number
new_groups: number
red_transfer: number
sensitive_words: number
del_customers: number
blocked_customers: number
voice_calls: number
}
/** 员工风控统计 kind 明细(GET /api/staff-stats?kind=…,行结构随 kind 变化)。 */
export interface StaffStatsDetail {
kind: string
rows: Record<string, unknown>[]
}