feat: improve model price error UX with role-aware messages and cleaner UI
- Backend: differentiate error messages for admin vs regular users in price.go - Backend: include error_code in channel test response for structured error handling - Frontend: render model_price_error as a styled card in Playground with admin nav button - Frontend: show inline error details and settings link in channel test modal - Frontend: parse error codes from both SSE and non-streaming API responses - i18n: remove redundant "Settings" suffix from setting tab translations (en/fr/ru/ja/vi) - i18n: update "Group & Model Pricing" translations across all locales
This commit is contained in:
+5
-3
@@ -890,7 +890,7 @@ export const useChannelsData = () => {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const { success, message, time } = res.data;
|
||||
const { success, message, time, error_code } = res.data;
|
||||
|
||||
// 更新测试结果
|
||||
setModelTestResults((prev) => ({
|
||||
@@ -900,6 +900,7 @@ export const useChannelsData = () => {
|
||||
message,
|
||||
time: time || 0,
|
||||
timestamp: Date.now(),
|
||||
errorCode: error_code || null,
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -927,7 +928,7 @@ export const useChannelsData = () => {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
showError(`${t('模型')} ${model}: ${message}`);
|
||||
showError(message);
|
||||
}
|
||||
} catch (error) {
|
||||
// 处理网络错误
|
||||
@@ -939,9 +940,10 @@ export const useChannelsData = () => {
|
||||
message: error.message || t('网络错误'),
|
||||
time: 0,
|
||||
timestamp: Date.now(),
|
||||
errorCode: null,
|
||||
},
|
||||
}));
|
||||
showError(`${t('模型')} ${model}: ${error.message || t('测试失败')}`);
|
||||
showError(error.message || t('测试失败'));
|
||||
} finally {
|
||||
// 从正在测试的模型集合中移除
|
||||
setTestingModels((prev) => {
|
||||
|
||||
+43
-6
@@ -196,10 +196,17 @@ export const useApiRequest = (
|
||||
|
||||
if (!response.ok) {
|
||||
let errorBody = '';
|
||||
let parsedError = null;
|
||||
try {
|
||||
errorBody = await response.text();
|
||||
const errorJson = JSON.parse(errorBody);
|
||||
if (errorJson?.error) {
|
||||
parsedError = errorJson.error;
|
||||
}
|
||||
} catch (e) {
|
||||
errorBody = '无法读取错误响应体';
|
||||
if (!errorBody) {
|
||||
errorBody = '无法读取错误响应体';
|
||||
}
|
||||
}
|
||||
|
||||
const errorInfo = handleApiError(
|
||||
@@ -215,9 +222,13 @@ export const useApiRequest = (
|
||||
}));
|
||||
setActiveDebugTab(DEBUG_TABS.RESPONSE);
|
||||
|
||||
throw new Error(
|
||||
`HTTP error! status: ${response.status}, body: ${errorBody}`,
|
||||
const err = new Error(
|
||||
parsedError?.message ||
|
||||
`HTTP error! status: ${response.status}, body: ${errorBody}`,
|
||||
);
|
||||
err.errorCode = parsedError?.code || null;
|
||||
err.errorType = parsedError?.type || null;
|
||||
throw err;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
@@ -277,6 +288,7 @@ export const useApiRequest = (
|
||||
newMessages[newMessages.length - 1] = {
|
||||
...lastMessage,
|
||||
content: t('请求发生错误: ') + error.message,
|
||||
errorCode: error.errorCode || null,
|
||||
status: MESSAGE_STATUS.ERROR,
|
||||
...autoCollapseState,
|
||||
};
|
||||
@@ -379,7 +391,20 @@ export const useApiRequest = (
|
||||
// 只有在流没有正常完成且连接状态异常时才处理错误
|
||||
if (!isStreamComplete && source.readyState !== 2) {
|
||||
console.error('SSE Error:', e);
|
||||
const errorMessage = e.data || t('请求发生错误');
|
||||
let errorMessage = e.data || t('请求发生错误');
|
||||
let errorCode = null;
|
||||
|
||||
if (e.data) {
|
||||
try {
|
||||
const errorJson = JSON.parse(e.data);
|
||||
if (errorJson?.error) {
|
||||
errorMessage = errorJson.error.message || errorMessage;
|
||||
errorCode = errorJson.error.code || null;
|
||||
}
|
||||
} catch (_) {
|
||||
// not JSON, use raw data as error message
|
||||
}
|
||||
}
|
||||
|
||||
const errorInfo = handleApiError(new Error(errorMessage));
|
||||
errorInfo.readyState = source.readyState;
|
||||
@@ -393,8 +418,19 @@ export const useApiRequest = (
|
||||
}));
|
||||
setActiveDebugTab(DEBUG_TABS.RESPONSE);
|
||||
|
||||
streamMessageUpdate(errorMessage, 'content');
|
||||
completeMessage(MESSAGE_STATUS.ERROR);
|
||||
setMessage((prevMessage) => {
|
||||
const newMessages = [...prevMessage];
|
||||
const lastMessage = newMessages[newMessages.length - 1];
|
||||
if (lastMessage && lastMessage.status !== MESSAGE_STATUS.COMPLETE && lastMessage.status !== MESSAGE_STATUS.ERROR) {
|
||||
newMessages[newMessages.length - 1] = {
|
||||
...lastMessage,
|
||||
content: (lastMessage.content || '') + errorMessage,
|
||||
errorCode: errorCode,
|
||||
status: MESSAGE_STATUS.ERROR,
|
||||
};
|
||||
}
|
||||
return newMessages;
|
||||
});
|
||||
sseSourceRef.current = null;
|
||||
source.close();
|
||||
}
|
||||
@@ -446,6 +482,7 @@ export const useApiRequest = (
|
||||
[
|
||||
setDebugData,
|
||||
setActiveDebugTab,
|
||||
setMessage,
|
||||
streamMessageUpdate,
|
||||
completeMessage,
|
||||
t,
|
||||
|
||||
Reference in New Issue
Block a user