Compare commits

...

2 Commits

2 changed files with 84 additions and 23 deletions

View File

@@ -13,11 +13,44 @@ function createClient(): AxiosInstance {
instance.interceptors.request.use((request) => {
const { apiKey } = getRuntimeConfig()
const requestId = crypto.randomUUID()
if (apiKey) request.headers['x-api-key'] = apiKey
request.headers['x-request-id'] = crypto.randomUUID()
request.headers['x-request-id'] = requestId
request.headers['x-client-name'] = 'fabric-frontend'
console.info('[api:request]', {
method: request.method,
url: `${request.baseURL ?? ''}${request.url ?? ''}`,
requestId,
})
return request
})
instance.interceptors.response.use(
(response) => {
const requestId = response.headers['x-request-id'] ?? response.config.headers['x-request-id']
console.info('[api:response]', {
method: response.config.method,
url: `${response.config.baseURL ?? ''}${response.config.url ?? ''}`,
status: response.status,
requestId,
})
return response
},
(error) => {
const response = error?.response
const config = error?.config ?? {}
const requestId = response?.headers?.['x-request-id'] ?? config?.headers?.['x-request-id']
console.error('[api:error]', {
method: config.method,
url: `${config.baseURL ?? ''}${config.url ?? ''}`,
status: response?.status,
requestId,
})
return Promise.reject(error)
},
)
return instance
}

View File

@@ -26,6 +26,8 @@ export default function ChatPage() {
const [socketState, setSocketState] = useState<'offline' | 'online'>('offline')
const [onlineCount, setOnlineCount] = useState(0)
const [typingUsers, setTypingUsers] = useState<string[]>([])
const [loading, setLoading] = useState(false)
const [error, setError] = useState('')
const [seqFrom, setSeqFrom] = useState('1')
const [seqTo, setSeqTo] = useState('999999')
const [limit, setLimit] = useState('50')
@@ -86,6 +88,9 @@ export default function ChatPage() {
async function pullMessages() {
if (!channelId) return
setLoading(true)
setError('')
try {
const res = await getApiClient().get(`/channels/${channelId}/messages`, {
params: {
seq_from: Number(seqFrom || '1'),
@@ -95,31 +100,51 @@ export default function ChatPage() {
})
setMessages(res.data.items ?? [])
setPageInfo(res.data.page ?? null)
} catch {
setError('消息拉取失败')
} finally {
setLoading(false)
}
}
async function sendMessage() {
if (!channelId || !content.trim()) return
setError('')
try {
await getApiClient().post(`/channels/${channelId}/messages`, {
content,
authorUserId: 'frontend-user',
})
socket.emit('typing.stop', { channelId })
setContent('')
} catch {
setError('发送失败')
}
}
async function editMessage() {
if (!channelId || !editingMessageId || !editingContent.trim()) return
setError('')
try {
await getApiClient().patch(`/channels/${channelId}/messages/${editingMessageId}`, {
content: editingContent,
})
setEditingContent('')
await pullMessages()
} catch {
setError('编辑失败')
}
}
async function deleteMessage(messageId: string) {
if (!channelId || !messageId) return
setError('')
try {
await getApiClient().delete(`/channels/${channelId}/messages/${messageId}`)
await pullMessages()
} catch {
setError('删除失败')
}
}
function onChangeChannel(value: string) {
@@ -155,6 +180,8 @@ export default function ChatPage() {
<p>Guild: {guildId || '-'}</p>
<p>Socket: {socketState}</p>
<p>线: {onlineCount}</p>
{loading ? <p>...</p> : null}
{error ? <p style={{ color: 'crimson' }}>{error}</p> : null}
{typingUsers.length ? <p>: {typingUsers.join(', ')}</p> : null}
<div style={{ display: 'flex', gap: 8, marginBottom: 8 }}>
<input value={channelId} onChange={(e) => onChangeChannel(e.target.value)} placeholder="Channel ID" />
@@ -186,6 +213,7 @@ export default function ChatPage() {
</li>
))}
</ul>
{!loading && !messages.length ? <p></p> : null}
{pageInfo ? (
<p>
next_expected_seq: {pageInfo.nextExpectedSeq ?? '-'} | highest_committed_seq:{' '}