feat: 1. 将大部分的请求从fetch改成axios方便管理。

2. 给文档类型添加入口模块和相关数据的渲染。并且给文档类型进行功能上的角色权限区分
3. 新增角色权限管理页面
This commit is contained in:
2025-11-20 20:34:31 +08:00
parent 2e604e8ede
commit 3850d05bdd
25 changed files with 2299 additions and 762 deletions
+139 -141
View File
@@ -1,6 +1,7 @@
import { CHAT_CONFIG, ContentType, SSE_TIMEOUT } from '../config/chat';
import type { Feedbacktype, ThoughtItem, VisionFile, MessageEnd, MessageReplace } from '../types/dify_chat';
import { unicodeToChar } from '../utils/chat-utils';
import axios from 'axios';
// 基础请求选项
// 注意:客户端调用Remix API routes,不需要手动添加Authorization
@@ -321,7 +322,7 @@ const handleStream = (
* });
* ```
*/
const baseFetch = (url: string, fetchOptions: any, needAllResponseContent: boolean = false) => {
const baseFetch = async (url: string, fetchOptions: any, needAllResponseContent: boolean = false) => {
const options = Object.assign({}, baseOptions, fetchOptions);
// 调用Remix API routes(如 /api/conversations
@@ -329,51 +330,46 @@ const baseFetch = (url: string, fetchOptions: any, needAllResponseContent: boole
const urlWithPrefix = `${CHAT_CONFIG.API_URL}/${url.replace(/^\//, '')}`;
const { body } = options;
let data = body;
if (body && typeof body === 'object') {
// 不再添加user参数,服务端会从JWT自动提取
options.body = JSON.stringify(body);
data = body;
}
return fetch(urlWithPrefix, options)
.then((res: Response) => {
if (!res.ok) {
console.error('❌ Request failed:', {
status: res.status,
statusText: res.statusText,
url: urlWithPrefix
});
if (res.status === 422) {
return res.text().then(text => {
let errorMessage = text;
try {
const data = JSON.parse(text);
errorMessage = data.message || data.error || text;
} catch (e) {
// 如果不是JSON,使用原始文本
}
throw new Error(errorMessage);
});
}
throw new Error(`${res.status}: ${res.statusText}`);
}
if (needAllResponseContent) {
return res.text().then(text => {
try {
return JSON.parse(text);
} catch (e) {
return text;
}
});
}
const data = res.json();
return data;
})
.catch((err) => {
console.error('❌ Request error:', err.message);
throw err;
try {
const response = await axios({
url: urlWithPrefix,
method: options.method || 'GET',
data: data,
headers: options.headers,
withCredentials: true, // 等同于 credentials: 'include'
});
if (needAllResponseContent) {
return response.data;
}
return response.data;
} catch (err) {
if (axios.isAxiosError(err)) {
console.error('❌ Request failed:', {
status: err.response?.status,
statusText: err.response?.statusText,
url: urlWithPrefix
});
if (err.response?.status === 422) {
const errorData = err.response.data;
const errorMessage = errorData?.message || errorData?.error || JSON.stringify(errorData);
throw new Error(errorMessage);
}
throw new Error(`${err.response?.status || 500}: ${err.response?.statusText || err.message}`);
}
console.error('❌ Request error:', (err as Error).message);
throw err;
}
};
/**
@@ -532,25 +528,25 @@ export const fetchConversations = async () => {
const url = `${CHAT_CONFIG.API_URL}/conversations?${params}`;
console.log('📋 [API Client] 获取会话列表:', { url, apiUrl: CHAT_CONFIG.API_URL });
return fetch(url, {
method: 'GET',
credentials: 'include', // 携带cookie
}).then(res => {
console.log('📋 [API Client] 会话列表响应:', { status: res.status, ok: res.ok });
if (!res.ok) {
return res.text().then(text => {
console.error('❌ [API Client] 获取会话列表失败:', { status: res.status, body: text });
throw new Error(`Failed to fetch conversations: ${res.status} - ${text}`);
});
}
return res.json().then(data => {
console.log('📋 [API Client] 会话列表数据:', data);
return data;
try {
const response = await axios.get(url, {
withCredentials: true, // 携带cookie
});
}).catch(err => {
console.log('📋 [API Client] 会话列表响应:', { status: response.status });
console.log('📋 [API Client] 会话列表数据:', response.data);
return response.data;
} catch (err) {
if (axios.isAxiosError(err)) {
console.error('❌ [API Client] 获取会话列表失败:', {
status: err.response?.status,
body: err.response?.data
});
throw new Error(`Failed to fetch conversations: ${err.response?.status} - ${JSON.stringify(err.response?.data)}`);
}
console.error('❌ [API Client] 会话列表请求异常:', err);
throw err;
});
}
};
/**
@@ -582,15 +578,17 @@ export const fetchChatList = async (conversationId: string) => {
// 不再传递user参数,服务端会从JWT自动提取
});
return fetch(`${CHAT_CONFIG.API_URL}/messages?${params}`, {
method: 'GET',
credentials: 'include', // 携带cookie
}).then(res => {
if (!res.ok) {
throw new Error(`Failed to fetch chat list: ${res.status}`);
try {
const response = await axios.get(`${CHAT_CONFIG.API_URL}/messages?${params}`, {
withCredentials: true, // 携带cookie
});
return response.data;
} catch (err) {
if (axios.isAxiosError(err)) {
throw new Error(`Failed to fetch chat list: ${err.response?.status}`);
}
return res.json();
});
throw err;
}
};
/**
@@ -620,25 +618,24 @@ export const fetchAppParams = async () => {
const url = `${CHAT_CONFIG.API_URL}/parameters`;
console.log('⚙️ [API Client] 获取应用参数:', { url, apiUrl: CHAT_CONFIG.API_URL });
return fetch(url, {
method: 'GET',
credentials: 'include', // 携带cookie
}).then(res => {
console.log('⚙️ [API Client] 应用参数响应:', { status: res.status, ok: res.ok });
if (!res.ok) {
return res.text().then(text => {
console.error('❌ [API Client] 获取应用参数失败:', { status: res.status, body: text });
throw new Error(`Failed to fetch app params: ${res.status} - ${text}`);
});
}
return res.json().then(data => {
console.log('⚙️ [API Client] 应用参数数据:', data);
return data;
try {
const response = await axios.get(url, {
withCredentials: true, // 携带cookie
});
}).catch(err => {
console.log('⚙️ [API Client] 应用参数响应:', { status: response.status });
console.log('⚙️ [API Client] 应用参数数据:', response.data);
return response.data;
} catch (err) {
if (axios.isAxiosError(err)) {
console.error('❌ [API Client] 获取应用参数失败:', {
status: err.response?.status,
body: err.response?.data
});
throw new Error(`Failed to fetch app params: ${err.response?.status} - ${JSON.stringify(err.response?.data)}`);
}
console.error('❌ [API Client] 应用参数请求异常:', err);
throw err;
});
}
};
/**
@@ -669,19 +666,20 @@ export const fetchAppParams = async () => {
export const updateFeedback = async ({ url, body }: { url: string; body: Feedbacktype }) => {
const messageId = url.split('/').pop(); // 从URL中提取messageId
return fetch(`${CHAT_CONFIG.API_URL}/messages/${messageId}/feedbacks`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include', // 携带cookie
body: JSON.stringify(body), // 不再添加user参数
}).then(res => {
if (!res.ok) {
throw new Error(`Failed to update feedback: ${res.status}`);
try {
const response = await axios.post(`${CHAT_CONFIG.API_URL}/messages/${messageId}/feedbacks`, body, {
headers: {
'Content-Type': 'application/json',
},
withCredentials: true, // 携带cookie
});
return response.data;
} catch (err) {
if (axios.isAxiosError(err)) {
throw new Error(`Failed to update feedback: ${err.response?.status}`);
}
return res.json();
});
throw err;
}
};
/**
@@ -705,22 +703,23 @@ export const updateFeedback = async ({ url, body }: { url: string; body: Feedbac
* ```
*/
export const generateConversationName = async (id: string) => {
return fetch(`${CHAT_CONFIG.API_URL}/conversations/${id}/name`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include', // 携带cookie
body: JSON.stringify({
try {
const response = await axios.post(`${CHAT_CONFIG.API_URL}/conversations/${id}/name`, {
auto_generate: true,
// 不再添加user参数
}),
}).then(res => {
if (!res.ok) {
throw new Error(`Failed to generate conversation name: ${res.status}`);
}, {
headers: {
'Content-Type': 'application/json',
},
withCredentials: true, // 携带cookie
});
return response.data;
} catch (err) {
if (axios.isAxiosError(err)) {
throw new Error(`Failed to generate conversation name: ${err.response?.status}`);
}
return res.json();
});
throw err;
}
};
/**
@@ -749,23 +748,24 @@ export const generateConversationName = async (id: string) => {
* ```
*/
export const renameConversation = async (id: string, name: string, autoGenerate: boolean = false) => {
return fetch(`${CHAT_CONFIG.API_URL}/conversations/${id}/name`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include', // 携带cookie
body: JSON.stringify({
try {
const response = await axios.post(`${CHAT_CONFIG.API_URL}/conversations/${id}/name`, {
name: autoGenerate ? undefined : name,
auto_generate: autoGenerate,
// 不再添加user参数
}),
}).then(res => {
if (!res.ok) {
throw new Error(`Failed to rename conversation: ${res.status}`);
}, {
headers: {
'Content-Type': 'application/json',
},
withCredentials: true, // 携带cookie
});
return response.data;
} catch (err) {
if (axios.isAxiosError(err)) {
throw new Error(`Failed to rename conversation: ${err.response?.status}`);
}
return res.json();
});
throw err;
}
};
/**
@@ -790,31 +790,29 @@ export const renameConversation = async (id: string, name: string, autoGenerate:
export const deleteConversation = async (id: string) => {
console.log('🗑️ [API Client] 删除会话:', id);
return fetch(`${CHAT_CONFIG.API_URL}/conversations/${id}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include', // 携带cookie
// 不再发送body和user参数
}).then(async res => {
console.log('🗑️ [API Client] 删除会话响应:', {
status: res.status,
ok: res.ok,
statusText: res.statusText
try {
const response = await axios.delete(`${CHAT_CONFIG.API_URL}/conversations/${id}`, {
headers: {
'Content-Type': 'application/json',
},
withCredentials: true, // 携带cookie
// 不再发送body和user参数
});
if (!res.ok) {
// 尝试读取错误详情
const errorText = await res.text();
console.error('❌ [API Client] 删除会话失败详情:', errorText);
throw new Error(`Failed to delete conversation: ${res.status}`);
}
console.log('🗑️ [API Client] 删除会话响应:', {
status: response.status,
statusText: response.statusText
});
const data = await res.json();
console.log('🗑️ [API Client] 删除会话数据:', data);
return data;
});
console.log('🗑️ [API Client] 删除会话数据:', response.data);
return response.data;
} catch (err) {
if (axios.isAxiosError(err)) {
console.error('❌ [API Client] 删除会话失败详情:', err.response?.data);
throw new Error(`Failed to delete conversation: ${err.response?.status}`);
}
throw err;
}
};
/**