feat: remaining frontend views (groups/calls/sms/sync) + messageout media fields
Backend (Part A): - MessageOut: add file_th_url, file_hd_url, duration, transcription_text, md5 (room_id + sender_head_url already existed) so the chat timeline can render image thumbnails, voice duration/transcription, and avatars from a single response. - PhoneCallOut: add record_file so the Calls view can offer recording playback. - SmsOut: add content (full body) so the SMS detail dialog shows the whole text. - Tests: red->green for each new field (media fields default None + populated, record_file round-trip, content round-trip). Suite 267 -> 271. Frontend (Part B): - api/index.ts: wrappers getGroups/getGroupMembers/getCalls/getSms/getSyncStatus + Group/GroupMember/PhoneCall/Sms/SyncState/SyncRun/SyncStatus types in types.ts (mirror the *Out pydantic schemas). - views/GroupList.vue (/groups): table + channel filter + pagination; row click opens the group timeline. - views/CallList.vue (/calls): table + call-type filter (phone_call/voice_call/ all); "播放录音" action opens an el-dialog with <audio controls>. - views/SmsList.vue (/sms): table; row click opens a detail dialog with the full content. - views/SyncStatus.vue (/sync): two tables (states + recent_runs) with a manual refresh; run status color-coded. - ChatTimeline.vue: reused for both 1:1 DM (talkerId) and group (roomId) by branching the query; group title + per-member sender already handled by MessageBubble. - router: add /groups /calls /sms /sync + /group/:channel/:ownerId/:roomId. - layouts/MainLayout.vue: replace the single 客户列表 button with an el-menu (客户 / 群 / 通话 / 短信 / 同步); org tree kept on the left. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -45,3 +45,68 @@ export function channelLabel(channel?: string | null): string {
|
||||
return channel ?? '未知'
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Phone / voice call rendering
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Call-type (PhoneCall.channel) label — 电话 vs 语音通话. */
|
||||
export function callTypeLabel(channel?: string | null): string {
|
||||
switch (channel) {
|
||||
case 'phone_call':
|
||||
return '电话'
|
||||
case 'voice_call':
|
||||
return '语音通话'
|
||||
default:
|
||||
return channel ?? '未知'
|
||||
}
|
||||
}
|
||||
|
||||
/** Call direction. ``incoming_call``: 1 = 呼入 (incoming), 0 = 呼出 (outgoing). */
|
||||
export function callDirectionLabel(incoming?: number | null): string {
|
||||
if (incoming == null) return '--'
|
||||
return incoming === 1 ? '呼入' : '呼出'
|
||||
}
|
||||
|
||||
/**
|
||||
* Call status. The upstream schema uses 1 = 已接通 (answered/connected) and
|
||||
* 0 = 未接通 (missed/failed); other codes fall back to the raw value so the UI
|
||||
* never hides information.
|
||||
*/
|
||||
export function callStatusLabel(status?: number | null): string {
|
||||
if (status == null) return '--'
|
||||
switch (status) {
|
||||
case 1:
|
||||
return '已接通'
|
||||
case 0:
|
||||
return '未接通'
|
||||
default:
|
||||
return `状态 ${status}`
|
||||
}
|
||||
}
|
||||
|
||||
/** Render call_duration (seconds) as `N"s` / `M'SS"`; ``--`` when missing. */
|
||||
export function formatCallDuration(seconds?: number | null): string {
|
||||
if (!seconds || !Number.isFinite(seconds) || seconds <= 0) return '--'
|
||||
return formatDuration(seconds)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SMS rendering
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* SMS direction. Conventions: ``direction`` 1 = 发送 (outbound, staff →
|
||||
* customer), 0 = 接收 (inbound). Other values fall back to the raw code.
|
||||
*/
|
||||
export function smsDirectionLabel(direction?: number | null): string {
|
||||
if (direction == null) return '--'
|
||||
switch (direction) {
|
||||
case 1:
|
||||
return '发送'
|
||||
case 0:
|
||||
return '接收'
|
||||
default:
|
||||
return `方向 ${direction}`
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user