给所有请求都加上jwt,隐藏生成jwt的secret(放到.env中),隐藏app-secret(放在pm2运行配置文件中,后续直接读取环境配置即可)

This commit is contained in:
2025-10-17 15:28:22 +08:00
parent 9ec6d30573
commit 59706b70d0
70 changed files with 2279 additions and 688 deletions
+7 -4
View File
@@ -462,7 +462,7 @@ const FALLBACK_MENU_DATA: Record<string, MenuItem[]> = {
* @param roleKey 角色标识 (如: 'admin', 'common', 'deptLeader', 'groupLeader')
* @returns 用户可访问的路由列表
*/
export async function getUserRoutesByRole(roleKey: string): Promise<{ success: boolean; data?: MenuItem[]; error?: string; shouldRedirectToHome?: boolean }> {
export async function getUserRoutesByRole(roleKey: string, jwt?: string): Promise<{ success: boolean; data?: MenuItem[]; error?: string; shouldRedirectToHome?: boolean }> {
try {
console.log(`获取角色 ${roleKey} 的路由权限`);
@@ -470,7 +470,8 @@ export async function getUserRoutesByRole(roleKey: string): Promise<{ success: b
const roleResult = await postgrestGet<Array<{id: number}>>("roles", {
filter: {
"role_key": `eq.${roleKey}`
}
},
token: jwt
});
if (roleResult.error || !roleResult.data || roleResult.data.length === 0) {
@@ -485,7 +486,8 @@ export async function getUserRoutesByRole(roleKey: string): Promise<{ success: b
const roleRoutesResult = await postgrestGet<Array<{route_id: number}>>("role_route", {
filter: {
"role_id": `eq.${roleId}`
}
},
token: jwt
});
if (roleRoutesResult.error) {
@@ -509,7 +511,8 @@ export async function getUserRoutesByRole(roleKey: string): Promise<{ success: b
"id": `in.(${routeIds.join(',')})`,
"is_menu": "eq.1"
},
order: "parent_id,meta->>order"
order: "parent_id,meta->>order",
token: jwt
});
if (routesResult.error) {
+10 -7
View File
@@ -386,15 +386,18 @@ export async function del<T>(endpoint: string, params?: QueryParams): Promise<Ap
// 下载文件的方法
export async function downloadFile(path: string): Promise<Blob> {
const downloadUrl = `${DOCUMENT_URL}${path}`;
// 使用 PDF 代理路由获取文件,自动添加 JWT 认证
const downloadUrl = `/api/pdf-proxy?path=${encodeURIComponent(path)}`;
try {
// console.log(`📦 axios-client.ts->下载文件: ${downloadUrl}`);
const response = await axios.get(downloadUrl, {
responseType: 'blob'
});
return response.data;
const response = await fetch(downloadUrl);
if (!response.ok) {
throw new Error(`下载失败: ${response.status} ${response.statusText}`);
}
return await response.blob();
} catch (error) {
console.error('下载文件失败:', error);
throw error;
+33 -14
View File
@@ -58,6 +58,7 @@ export interface TemplateSearchParams {
pageSize?: number;
sortBy?: string;
sortOrder?: 'asc' | 'desc';
token?: string; // JWT token
}
export interface SearchResult {
@@ -70,12 +71,14 @@ export interface SearchResult {
/**
* 获取所有合同分类
* @param jwt JWT token (可选)
*/
export async function getContractCategories() {
export async function getContractCategories(jwt?: string) {
try {
const params: PostgrestParams = {
select: '*',
order: 'sort_order.asc,name.asc'
order: 'sort_order.asc,name.asc',
token: jwt
};
const response = await postgrestGet<ContractCategory[]>('contract_categories', params);
@@ -98,13 +101,15 @@ export async function getContractCategories() {
/**
* 获取所有合同分类及其模板数量(使用聚合查询)
* @param jwt JWT token (可选)
*/
export async function getContractCategoriesWithCount() {
export async function getContractCategoriesWithCount(jwt?: string) {
try {
// 获取所有分类
const categoriesResponse = await postgrestGet<ContractCategory[]>('contract_categories', {
select: '*',
order: 'sort_order.asc,name.asc'
order: 'sort_order.asc,name.asc',
token: jwt
});
if (categoriesResponse.error) {
@@ -120,7 +125,8 @@ export async function getContractCategoriesWithCount() {
// 简化方案:获取该分类下的所有模板ID,然后计算数量
const countResponse = await postgrestGet<{ id: number }[]>('contract_templates', {
select: 'id',
filter: { 'category_id': `eq.${category.id}` }
filter: { 'category_id': `eq.${category.id}` },
token: jwt
});
let templateCount = 0;
@@ -172,7 +178,8 @@ export async function getContractTemplates(searchParams: TemplateSearchParams =
page = 1,
pageSize = 6,
sortBy = 'updated_at',
sortOrder = 'desc'
sortOrder = 'desc',
token
} = searchParams;
// 构建查询参数
@@ -180,7 +187,8 @@ export async function getContractTemplates(searchParams: TemplateSearchParams =
select: 'id,template_code,title,category_id,description,file_path,file_format,is_featured,created_at,updated_at,pdf_file_path,category:contract_categories(id,name,icon,description)',
limit: pageSize,
offset: (page - 1) * pageSize,
order: `${sortBy}.${sortOrder}`
order: `${sortBy}.${sortOrder}`,
token
};
// 构建过滤条件
@@ -207,7 +215,8 @@ export async function getContractTemplates(searchParams: TemplateSearchParams =
try {
const categoryResponse = await postgrestGet<ContractCategory[]>('contract_categories', {
select: 'id',
filter: { 'name': `ilike.*${cleanKeyword}*` }
filter: { 'name': `ilike.*${cleanKeyword}*` },
token
});
if (categoryResponse.data) {
@@ -237,7 +246,8 @@ export async function getContractTemplates(searchParams: TemplateSearchParams =
if (category && !category_id) {
const categoryResponse = await postgrestGet<ContractCategory[]>('contract_categories', {
select: 'id',
filter: { 'name': `eq.${category}` }
filter: { 'name': `eq.${category}` },
token
});
if (categoryResponse.data) {
@@ -265,7 +275,8 @@ export async function getContractTemplates(searchParams: TemplateSearchParams =
const countParams: PostgrestParams = {
select: 'id',
filter: params.filter,
or: params.or
or: params.or,
token
};
const countResponse = await postgrestGet<{ id: number }[]>('contract_templates', countParams);
@@ -295,12 +306,15 @@ export async function getContractTemplates(searchParams: TemplateSearchParams =
/**
* 根据ID获取单个合同模板
* @param id 模板ID
* @param jwt JWT token (可选)
*/
export async function getContractTemplate(id: string | number) {
export async function getContractTemplate(id: string | number, jwt?: string) {
try {
const params: PostgrestParams = {
select: 'id,template_code,title,category_id,description,file_path,file_format,is_featured,created_at,updated_at,pdf_file_path,category:contract_categories(id,name,icon,description)',
filter: { 'id': `eq.${id}` }
filter: { 'id': `eq.${id}` },
token: jwt
};
const response = await postgrestGet<ContractTemplate[]>('contract_templates', params);
@@ -327,14 +341,17 @@ export async function getContractTemplate(id: string | number) {
/**
* 获取推荐模板
* @param limit 数量限制
* @param jwt JWT token (可选)
*/
export async function getFeaturedTemplates(limit: number = 6) {
export async function getFeaturedTemplates(limit: number = 6, jwt?: string) {
try {
const params: PostgrestParams = {
select: 'id,template_code,title,category_id,description,file_path,file_format,is_featured,created_at,updated_at,pdf_file_path,category:contract_categories(id,name,icon,description)',
filter: { 'is_featured': 'eq.true' },
order: 'updated_at.desc',
limit
limit,
token: jwt
};
const response = await postgrestGet<ContractTemplate[]>('contract_templates', params);
@@ -357,6 +374,8 @@ export async function getFeaturedTemplates(limit: number = 6) {
/**
* 搜索合同模板(智能搜索)
* @param query 搜索关键词
* @param filters 过滤条件
*/
export async function searchContractTemplates(
query: string,
+6 -4
View File
@@ -87,13 +87,14 @@ async function safeGetJWT(jwtToken?: string): Promise<string> {
* @param userId 用户ID
* @returns 是否是发起人
*/
export async function findIsProposer(taskId: string | number, userId: number | undefined): Promise<boolean> {
export async function findIsProposer(taskId: string | number, userId: number | undefined, frontendJWT?: string): Promise<boolean> {
// 通过postgrest的get请求去cross_examination_tasks表中进行查找assignee_id是否等于userId
const response = await postgrestGet(`cross_examination_tasks`, {
select: 'assigner_id',
filter: {
id: `eq.${taskId}`
}
},
token: frontendJWT
});
if (response.error) {
console.error('获取任务数据失败:', response.error);
@@ -366,7 +367,8 @@ export async function performOpinionAction(
* @returns 完成评查结果
*/
export async function confirmReviewResults(
documentId: string | number
documentId: string | number,
frontendJWT?: string
): Promise<{data?: unknown, error?: string, status?: number}> {
try {
// 通过postgrest的post请求去documents表中进行查找id等于documentId的数据,更新documents表的audit_status为1
@@ -374,7 +376,7 @@ export async function confirmReviewResults(
audit_status: 1
}, {
id: documentId
});
}, frontendJWT);
if(response.error) {
return {
error: response.error,
+5 -4
View File
@@ -482,7 +482,7 @@ export async function getTaskDocuments(taskId: number, page: number = 1, pageSiz
* @param auditStatus 审核状态
* @returns 更新结果
*/
export async function updateDocumentAuditStatus(id: string, auditStatus: number): Promise<{
export async function updateDocumentAuditStatus(id: string, auditStatus: number, frontendJWT?: string): Promise<{
success?: boolean;
error?: string;
status?: number;
@@ -491,13 +491,14 @@ export async function updateDocumentAuditStatus(id: string, auditStatus: number)
if (!id) {
return { error: '文件ID不能为空', status: 400 };
}
const response = await postgrestPut<TaskDocument, Partial<TaskDocument>>(
'documents',
{ audit_status: auditStatus },
{
{
id: parseInt(id)
}
},
frontendJWT
);
if (response.error) {
+111
View File
@@ -0,0 +1,111 @@
// app/api/db-client.server.ts
import { getUserSession } from '~/api/login/auth.server';
import { runWithContext } from './postgrest-client';
/**
* 在认证上下文中运行
*
* 所有在此上下文中调用的 postgrest 函数(postgrestGet/Post/Put/Delete
* 都会自动获取并添加 JWT Token 到 Authorization 头部
*
* @param request Remix Request 对象
* @param fn 要在认证上下文中执行的函数
* @returns 函数执行结果
* @throws 如果用户未登录则抛出错误
*
* @example
* ```typescript
* export async function loader({ request }: LoaderFunctionArgs) {
* return await runInAuthContext(request, async () => {
* // 所有 postgrest 调用自动带 JWT
* const users = await postgrestGet('users', { limit: 10 });
* const docs = await postgrestGet('documents', { filter: { status: 'eq.0' } });
*
* return json({ users: users.data, docs: docs.data });
* });
* }
* ```
*/
export async function runInAuthContext<T>(
request: Request,
fn: () => T | Promise<T>
): Promise<T> {
const { frontendJWT, isAuthenticated } = await getUserSession(request);
if (!isAuthenticated || !frontendJWT) {
throw new Error('用户未登录,无法执行需要认证的操作');
}
// 在上下文中设置 JWT,所有 postgrest 调用都会自动使用
return runWithContext({ jwt: frontendJWT }, fn);
}
/**
* 在公开上下文中运行(不需要认证)
*
* 用于公开数据访问,不会添加 JWT Token
*
* @param fn 要执行的函数
* @returns 函数执行结果
*
* @example
* ```typescript
* export async function loader() {
* return runInPublicContext(async () => {
* const articles = await postgrestGet('public_articles', {
* filter: { published: 'eq.true' }
* });
* return json({ articles: articles.data });
* });
* }
* ```
*/
export function runInPublicContext<T>(
fn: () => T | Promise<T>
): T | Promise<T> {
// 在空上下文中运行,不设置 JWT
return runWithContext({}, fn);
}
/**
* 在可选认证上下文中运行
*
* 如果用户已登录,会自动添加 JWT;
* 如果用户未登录,则不添加 JWT(不会抛出错误)
*
* @param request Remix Request 对象
* @param fn 要执行的函数
* @returns 函数执行结果
*
* @example
* ```typescript
* export async function loader({ request }: LoaderFunctionArgs) {
* return await runInOptionalAuthContext(request, async () => {
* // 如果用户登录,会带 JWT(可能看到更多内容)
* // 如果用户未登录,不带 JWT(看到基础内容)
* const content = await postgrestGet('content', { limit: 20 });
* return json({ content: content.data });
* });
* }
* ```
*/
export async function runInOptionalAuthContext<T>(
request: Request,
fn: () => T | Promise<T>
): Promise<T> {
try {
const { frontendJWT, isAuthenticated } = await getUserSession(request);
if (isAuthenticated && frontendJWT) {
// 用户已登录,使用 JWT
return runWithContext({ jwt: frontendJWT }, fn);
}
} catch (error) {
// 获取会话失败,继续以公开方式运行
console.warn('获取用户会话失败,以公开方式运行:', error);
}
// 用户未登录或获取会话失败,以公开方式运行
return runWithContext({}, fn);
}
+45 -34
View File
@@ -90,18 +90,20 @@ function extractApiData<T>(responseData: unknown): T | null {
/**
* 获取所有评查点分组
* @param token JWT token (可选)
* @returns 评查点分组列表
*/
export async function getAllEvaluationPointGroups(): Promise<{
export async function getAllEvaluationPointGroups(token?: string): Promise<{
data?: DocumentTypeGroup[];
error?: string;
status?: number;
}> {
try {
const params: PostgrestParams = {
select: 'id, name'
select: 'id, name',
token
};
const response = await postgrestGet<Array<{
id: number;
name: string;
@@ -137,9 +139,10 @@ export async function getAllEvaluationPointGroups(): Promise<{
/**
* 根据ID获取评查点分组信息
* @param ids 评查点分组ID数组
* @param token JWT token (可选)
* @returns 评查点分组信息
*/
export async function getEvaluationPointGroupsByIds(ids: number[] | number): Promise<{
export async function getEvaluationPointGroupsByIds(ids: number[] | number, token?: string): Promise<{
data?: DocumentTypeGroup[];
error?: string;
status?: number;
@@ -149,24 +152,25 @@ export async function getEvaluationPointGroupsByIds(ids: number[] | number): Pro
if (!ids) {
return { data: [] };
}
// 将单个ID转换为数组
const idsArray = Array.isArray(ids) ? ids : [ids];
if (idsArray.length === 0) {
return { data: [] };
}
// console.log('获取评查点分组,ID类型:', typeof ids, '转换后的ID数组:', idsArray);
const params: PostgrestParams = {
select: 'id, name',
filter: {
'id': `in.(${idsArray.join(',')})`
}
},
token
};
// console.log('获取评查点分组,查询参数:', params);
const response = await postgrestGet<Array<{
id: number;
name: string;
@@ -204,7 +208,7 @@ export async function getEvaluationPointGroupsByIds(ids: number[] | number): Pro
* @param searchParams 搜索参数
* @returns 文档类型列表和总数
*/
export async function getDocumentTypes(searchParams: DocumentTypeSearchParams = {}): Promise<{
export async function getDocumentTypes(searchParams: DocumentTypeSearchParams = {}, frontendJWT?: string): Promise<{
data?: { types: DocumentTypeUI[], total: number };
error?: string;
status?: number;
@@ -231,7 +235,8 @@ export async function getDocumentTypes(searchParams: DocumentTypeSearchParams =
},
limit: pageSize,
offset: (page - 1) * pageSize,
filter: {} as Record<string, string>
filter: {} as Record<string, string>,
token: frontendJWT
};
// 添加筛选条件
@@ -299,10 +304,10 @@ export async function getDocumentTypes(searchParams: DocumentTypeSearchParams =
}
// console.log(`文档类型 ${type.id} 的分组IDs:`, groupIds);
// 获取这些ID对应的分组信息
const groupsResponse = await getEvaluationPointGroupsByIds(groupIds);
const groupsResponse = await getEvaluationPointGroupsByIds(groupIds, frontendJWT);
// 返回包含分组信息的文档类型
return {
...type,
@@ -347,9 +352,10 @@ export async function getDocumentTypes(searchParams: DocumentTypeSearchParams =
/**
* 删除文档类型
* @param id 文档类型ID
* @param frontendJWT JWT token (可选)
* @returns 删除结果
*/
export async function deleteDocumentType(id: string): Promise<{
export async function deleteDocumentType(id: string, frontendJWT?: string): Promise<{
success?: boolean;
error?: string;
status?: number;
@@ -365,7 +371,8 @@ export async function deleteDocumentType(id: string): Promise<{
{
filter: {
'id': `eq.${id}`
}
},
token: frontendJWT
}
);
@@ -435,9 +442,10 @@ function convertToUIDocumentType(type: DocumentType & { groups: DocumentTypeGrou
/**
* 获取文档类型详情
* @param id 文档类型ID
* @param frontendJWT JWT token (可选)
* @returns 文档类型详情
*/
export async function getDocumentType(id: string): Promise<{
export async function getDocumentType(id: string, frontendJWT?: string): Promise<{
data?: DocumentTypeUI;
error?: string;
status?: number;
@@ -446,7 +454,7 @@ export async function getDocumentType(id: string): Promise<{
if (!id) {
return { error: '文档类型ID不能为空', status: 400 };
}
const params: PostgrestParams = {
select: `
id,
@@ -460,9 +468,10 @@ export async function getDocumentType(id: string): Promise<{
`,
filter: {
'id': `eq.${id}`
}
},
token: frontendJWT
};
const response = await postgrestGet<DocumentType[]>('document_types', params);
if (response.error) {
@@ -499,9 +508,9 @@ export async function getDocumentType(id: string): Promise<{
}
// console.log(`文档类型 ${id} 的分组IDs:`, groupIds);
const groupsResponse = await getEvaluationPointGroupsByIds(groupIds);
const groupsResponse = await getEvaluationPointGroupsByIds(groupIds, frontendJWT);
if (groupsResponse.error) {
return { error: groupsResponse.error, status: 500 };
}
@@ -527,7 +536,7 @@ export async function getDocumentType(id: string): Promise<{
* @param documentType 文档类型数据
* @returns 创建结果
*/
export async function createDocumentType(documentType: DocumentTypeCreateDTO): Promise<{
export async function createDocumentType(documentType: DocumentTypeCreateDTO, frontendJWT?: string): Promise<{
data?: DocumentTypeUI;
error?: string;
status?: number;
@@ -610,7 +619,8 @@ export async function createDocumentType(documentType: DocumentTypeCreateDTO): P
// 发送创建请求
const response = await postgrestPost<DocumentType, typeof apiDocumentType>(
'document_types',
apiDocumentType
apiDocumentType,
frontendJWT
);
if (response.error) {
@@ -628,14 +638,14 @@ export async function createDocumentType(documentType: DocumentTypeCreateDTO): P
}
// 获取关联分组信息
const groupsResponse = await getEvaluationPointGroupsByIds(groupIds);
const groupsResponse = await getEvaluationPointGroupsByIds(groupIds, frontendJWT);
// 添加分组信息并转换为UI类型
const typeWithGroups = {
...newDocumentType,
groups: groupsResponse.data || []
};
return { data: convertToUIDocumentType(typeWithGroups) };
} catch (error) {
console.error('创建文档类型失败:', error);
@@ -652,7 +662,7 @@ export async function createDocumentType(documentType: DocumentTypeCreateDTO): P
* @param documentType 文档类型数据
* @returns 更新结果
*/
export async function updateDocumentType(id: string, documentType: DocumentTypeUpdateDTO): Promise<{
export async function updateDocumentType(id: string, documentType: DocumentTypeUpdateDTO, frontendJWT?: string): Promise<{
data?: DocumentTypeUI;
error?: string;
status?: number;
@@ -730,7 +740,8 @@ export async function updateDocumentType(id: string, documentType: DocumentTypeU
const response = await postgrestPut<DocumentType, typeof apiDocumentType>(
'document_types',
apiDocumentType,
{id}
{id},
frontendJWT
);
if (response.error) {
@@ -748,14 +759,14 @@ export async function updateDocumentType(id: string, documentType: DocumentTypeU
}
// 获取关联分组信息
const groupsResponse = await getEvaluationPointGroupsByIds(groupIds);
const groupsResponse = await getEvaluationPointGroupsByIds(groupIds, frontendJWT);
// 添加分组信息并转换为UI类型
const typeWithGroups = {
...updatedDocumentType,
groups: groupsResponse.data || []
};
return { data: convertToUIDocumentType(typeWithGroups) };
} catch (error) {
console.error('更新文档类型失败:', error);
+26 -16
View File
@@ -129,9 +129,9 @@ interface ScoringProposal {
* @param request Remix请求对象,用于获取用户会话
* @returns 评查点结果列表和统计数据
*/
export async function getReviewPoints(fileId: string, request: Request) {
export async function getReviewPoints(fileId: string, request: Request) {
// 获取用户会话信息
const { userInfo } = await getUserSession(request);
const { userInfo, frontendJWT } = await getUserSession(request);
if (!userInfo?.user_id) {
console.error("用户身份验证失败");
@@ -141,7 +141,7 @@ export async function getReviewPoints(fileId: string, request: Request) {
// const userId = userInfo.user_id.toString();
// 首先先获取这个文档的数据
const documentData = await getDocumentWithNoUserId(fileId);
const documentData = await getDocumentWithNoUserId(fileId, frontendJWT);
if (documentData.error) {
console.error("获取文档数据错误:", documentData.error);
return Response.json({ error: documentData.error }, { status: documentData.status || 500 });
@@ -154,7 +154,8 @@ export async function getReviewPoints(fileId: string, request: Request) {
'document_id': `eq.${fileId}`
},
order: 'id.desc',
limit: 1
limit: 1,
token: frontendJWT
};
const contractStructureComparisonResponse = await postgrestGet('contract_structure_comparison', contractStructureComparisonParams);
@@ -195,7 +196,8 @@ export async function getReviewPoints(fileId: string, request: Request) {
select: '*',
filter: {
'document_id': `eq.${fileId}`
}
},
token: frontendJWT
};
const evaluationResultsResponse = await postgrestGet('evaluation_results', evaluationResultsParams);
@@ -223,7 +225,8 @@ export async function getReviewPoints(fileId: string, request: Request) {
select: '*',
filter: {
'id': `in.(${evaluationPointIds.join(',')})`
}
},
token: frontendJWT
};
const evaluationPointsResponse = await postgrestGet('evaluation_points', evaluationPointsParams);
@@ -249,7 +252,8 @@ export async function getReviewPoints(fileId: string, request: Request) {
select: '*',
filter: {
'id': `in.(${groupIds.join(',')})`
}
},
token: frontendJWT
};
const groupsResponse = await postgrestGet('evaluation_point_groups', groupsParams);
@@ -272,7 +276,8 @@ export async function getReviewPoints(fileId: string, request: Request) {
filter: {
'document_id': `eq.${fileId}`,
'evaluation_point_id': `in.(${manualReviewPointsIds.join(',')})`
}
},
token: frontendJWT
};
const manualReviewPointsResponse = await postgrestGet('audit_status', manualReviewPointsParams);
if (manualReviewPointsResponse.error) {
@@ -326,7 +331,8 @@ export async function getReviewPoints(fileId: string, request: Request) {
filter: {
'document_id': `eq.${fileId}`,
'deleted_at': `is.null`
}
},
token: frontendJWT
};
const scoringProposalsResponse = await postgrestGet('cross_scoring_proposals', scoringProposalsParams);
@@ -754,7 +760,7 @@ export async function updateReviewResult(
}> {
try {
// 获取用户会话信息
const { userInfo } = await getUserSession(request);
const { userInfo, frontendJWT } = await getUserSession(request);
if (!userInfo?.user_id) {
console.error("用户身份验证失败");
@@ -770,7 +776,8 @@ export async function updateReviewResult(
// 首先获取当前评查结果数据
const currentResultResponse = await postgrestGet('evaluation_results', {
select: '*',
filter: { id: `eq.${resultId}` }
filter: { id: `eq.${resultId}` },
token: frontendJWT
});
if (currentResultResponse.error) {
@@ -805,7 +812,8 @@ export async function updateReviewResult(
const resultResponse = await postgrestPut<unknown, typeof updatedData>(
'evaluation_results',
updatedData,
{ id: resultId }
{ id: resultId },
frontendJWT
);
if (resultResponse.error) {
@@ -830,7 +838,8 @@ export async function updateReviewResult(
{
id: editAuditStatusId,
user_id: userId // 添加用户ID条件,确保只能更新自己的记录
}
},
frontendJWT
);
if (auditStatusResponse.error) {
@@ -853,7 +862,7 @@ export async function updateReviewResult(
};
// 使用postgrestPost创建新记录
const postResponse = await postgrestPost('audit_status', newAuditStatus);
const postResponse = await postgrestPost('audit_status', newAuditStatus, frontendJWT);
if (postResponse.error) {
return { error: postResponse.error, status: postResponse.status || 500 };
@@ -889,7 +898,7 @@ export async function confirmReviewResults(documentId: string, request: Request)
}> {
try {
// 获取用户会话信息
const { userInfo } = await getUserSession(request);
const { userInfo, frontendJWT } = await getUserSession(request);
if (!userInfo?.user_id) {
console.error("用户身份验证失败");
@@ -932,7 +941,8 @@ export async function confirmReviewResults(documentId: string, request: Request)
{
id: documentId,
user_id: userId // 添加用户ID条件,确保只能更新自己的文档
}
},
frontendJWT
);
if (response.error) {
+49 -27
View File
@@ -68,9 +68,10 @@ function extractApiData<T>(responseData: unknown): T | null {
/**
* 获取评查点分组列表
* @param token JWT token (可选)
* @returns 评查点分组列表
*/
export async function getRuleGroups(): Promise<{data: RuleGroup[]; error?: never} | {data?: never; error: string; status?: number}> {
export async function getRuleGroups(token?: string): Promise<{data: RuleGroup[]; error?: never} | {data?: never; error: string; status?: number}> {
try {
const params: PostgrestParams = {
select: `
@@ -84,7 +85,8 @@ export async function getRuleGroups(): Promise<{data: RuleGroup[]; error?: never
`,
filter: {
'pid': 'eq.0'
}
},
token
};
const response = await postgrestGet<{code: number; msg: string; data: Array<{
@@ -138,9 +140,10 @@ export async function getRuleGroups(): Promise<{data: RuleGroup[]; error?: never
/**
* 获取指定分组的子分组
* @param parentId 父分组ID
* @param token JWT token (可选)
* @returns 子分组列表
*/
export async function getChildGroups(parentId: string): Promise<{data: RuleGroup[]; error?: never} | {data?: never; error: string; status?: number}> {
export async function getChildGroups(parentId: string, token?: string): Promise<{data: RuleGroup[]; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 1. 获取子分组
const childGroupsParams: PostgrestParams = {
@@ -154,7 +157,8 @@ export async function getChildGroups(parentId: string): Promise<{data: RuleGroup
`,
filter: {
'pid': `eq.${parentId}`
}
},
token
};
const childGroupsResponse = await postgrestGet<{code: number; msg: string; data: Array<{
@@ -179,7 +183,8 @@ export async function getChildGroups(parentId: string): Promise<{data: RuleGroup
select: 'id',
filter: {
'evaluation_point_groups_id': `eq.${group.id}`
}
},
token
};
const ruleCountResponse = await postgrestGet<ApiResponse<Array<{id: number}>>>('evaluation_points', ruleCountParams);
@@ -203,7 +208,8 @@ export async function getChildGroups(parentId: string): Promise<{data: RuleGroup
select: 'id',
filter: {
'evaluation_point_groups_id': `eq.${group.id}`
}
},
token
};
const ruleCountResponse = await postgrestGet<ApiResponse<Array<{id: number}>>>('evaluation_points', ruleCountParams);
@@ -234,9 +240,10 @@ export async function getChildGroups(parentId: string): Promise<{data: RuleGroup
/**
* 获取所有评查点分组(包括一级和二级)
* @param token JWT token (可选)
* @returns 完整的评查点分组列表
*/
export async function getAllRuleGroups(): Promise<{data: RuleGroup[]; error?: never} | {data?: never; error: string; status?: number}> {
export async function getAllRuleGroups(token?: string): Promise<{data: RuleGroup[]; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 1. 获取所有分组
const allGroupsParams: PostgrestParams = {
@@ -245,7 +252,8 @@ export async function getAllRuleGroups(): Promise<{data: RuleGroup[]; error?: ne
pid,
name,
is_enabled
`
`,
token
};
const allGroupsResponse = await postgrestGet<{code: number; msg: string; data: Array<{
@@ -292,7 +300,8 @@ export async function getAllRuleGroups(): Promise<{data: RuleGroup[]; error?: ne
select: 'id',
filter: {
'evaluation_point_groups_id': `eq.${child.id}`
}
},
token
};
const ruleCountResponse = await postgrestGet<ApiResponse<Array<{id: number}>>>('evaluation_points', ruleCountParams);
@@ -316,9 +325,10 @@ export async function getAllRuleGroups(): Promise<{data: RuleGroup[]; error?: ne
/**
* 获取单个评查点分组详情
* @param id 分组ID
* @param token JWT token (可选)
* @returns 分组详情
*/
export async function getRuleGroup(id: string): Promise<{data: RuleGroup; error?: never} | {data?: never; error: string; status?: number}> {
export async function getRuleGroup(id: string, token?: string): Promise<{data: RuleGroup; error?: never} | {data?: never; error: string; status?: number}> {
try {
if (!id) {
return { error: '分组ID不能为空', status: 400 };
@@ -336,7 +346,8 @@ export async function getRuleGroup(id: string): Promise<{data: RuleGroup; error?
`,
filter: {
'id': `eq.${id}`
}
},
token
};
const response = await postgrestGet<{code: number; msg: string; data: Array<{
@@ -389,7 +400,8 @@ export async function getRuleGroup(id: string): Promise<{data: RuleGroup; error?
select: 'id',
filter: {
'evaluation_point_groups_id': `eq.${group.id}`
}
},
token
};
const ruleCountResponse = await postgrestGet<ApiResponse<Array<{id: number}>>>('evaluation_points', ruleCountParams);
@@ -412,9 +424,10 @@ export async function getRuleGroup(id: string): Promise<{data: RuleGroup; error?
/**
* 创建评查点分组
* @param groupData 分组数据
* @param token JWT token (可选)
* @returns 创建的分组
*/
export async function createRuleGroup(groupData: RuleGroupCreateUpdateDto): Promise<{data: RuleGroup; error?: never} | {data?: never; error: string; status?: number}> {
export async function createRuleGroup(groupData: RuleGroupCreateUpdateDto, token?: string): Promise<{data: RuleGroup; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 验证必填字段
if (!groupData.name || !groupData.code) {
@@ -447,7 +460,8 @@ export async function createRuleGroup(groupData: RuleGroupCreateUpdateDto): Prom
// 直接发送到 PostgreSQL 表
const response = await postgrestPost<ApiResponse<ApiRuleGroup> | ApiRuleGroup, ApiRuleGroup>(
'evaluation_point_groups', // 表名
apiGroup
apiGroup,
token
);
if (response.error) {
@@ -490,15 +504,17 @@ export async function createRuleGroup(groupData: RuleGroupCreateUpdateDto): Prom
* 更新评查点分组
* @param id 分组ID
* @param data 更新的分组数据
* @param token JWT token (可选)
* @returns 更新后的分组
*/
export async function updateRuleGroup(id: string, data: RuleGroupCreateUpdateDto): Promise<{data: RuleGroup; error?: never} | {data?: never; error: string; status?: number}> {
export async function updateRuleGroup(id: string, data: RuleGroupCreateUpdateDto, token?: string): Promise<{data: RuleGroup; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 使用新的filters参数
const response = await postgrestPut<ApiResponse<RuleGroup> | RuleGroup, RuleGroupCreateUpdateDto>(
'evaluation_point_groups',
data,
{ id }
{ id },
token
);
if (response.error) {
@@ -524,12 +540,13 @@ export async function updateRuleGroup(id: string, data: RuleGroupCreateUpdateDto
/**
* 删除评查点分组
* @param id 分组ID
* @param token JWT token (可选)
* @returns 删除结果
*/
export async function deleteRuleGroup(id: string): Promise<{success: boolean; error?: string}> {
export async function deleteRuleGroup(id: string, token?: string): Promise<{success: boolean; error?: string}> {
try {
// 1. 首先获取分组信息,判断是一级还是二级分组
const groupResponse = await getRuleGroup(id);
const groupResponse = await getRuleGroup(id, token);
if (groupResponse.error) {
return { success: false, error: groupResponse.error };
}
@@ -542,7 +559,7 @@ export async function deleteRuleGroup(id: string): Promise<{success: boolean; er
// 2. 如果是一级分组,需要先删除所有子分组
if (group.pid === '0') {
// 获取所有子分组
const childGroupsResponse = await getChildGroups(id);
const childGroupsResponse = await getChildGroups(id, token);
if (childGroupsResponse.error) {
return { success: false, error: childGroupsResponse.error };
}
@@ -551,7 +568,7 @@ export async function deleteRuleGroup(id: string): Promise<{success: boolean; er
// 遍历删除每个子分组
for (const childGroup of childGroups) {
const deleteChildResult = await deleteChildGroup(childGroup.id);
const deleteChildResult = await deleteChildGroup(childGroup.id, token);
if (!deleteChildResult.success) {
return deleteChildResult;
}
@@ -559,7 +576,7 @@ export async function deleteRuleGroup(id: string): Promise<{success: boolean; er
}
// 3. 删除分组下的所有评查点
const deletePointsResult = await deleteEvaluationPointsByGroupId(id);
const deletePointsResult = await deleteEvaluationPointsByGroupId(id, token);
if (!deletePointsResult.success) {
return deletePointsResult;
}
@@ -568,7 +585,8 @@ export async function deleteRuleGroup(id: string): Promise<{success: boolean; er
const response = await postgrestDelete<ApiResponse<{id: number}>>('evaluation_point_groups', {
filter: {
'id': `eq.${id}`
}
},
token
});
if (response.error) {
@@ -588,12 +606,13 @@ export async function deleteRuleGroup(id: string): Promise<{success: boolean; er
/**
* 删除子分组及其相关数据
* @param id 子分组ID
* @param token JWT token (可选)
* @returns 删除结果
*/
async function deleteChildGroup(id: string): Promise<{success: boolean; error?: string}> {
async function deleteChildGroup(id: string, token?: string): Promise<{success: boolean; error?: string}> {
try {
// 1. 删除子分组下的所有评查点
const deletePointsResult = await deleteEvaluationPointsByGroupId(id);
const deletePointsResult = await deleteEvaluationPointsByGroupId(id, token);
if (!deletePointsResult.success) {
return deletePointsResult;
}
@@ -602,7 +621,8 @@ async function deleteChildGroup(id: string): Promise<{success: boolean; error?:
const response = await postgrestDelete<ApiResponse<{id: number}>>('evaluation_point_groups', {
filter: {
'id': `eq.${id}`
}
},
token
});
if (response.error) {
@@ -622,14 +642,16 @@ async function deleteChildGroup(id: string): Promise<{success: boolean; error?:
/**
* 删除指定分组下的所有评查点
* @param groupId 分组ID
* @param token JWT token (可选)
* @returns 删除结果
*/
async function deleteEvaluationPointsByGroupId(groupId: string): Promise<{success: boolean; error?: string}> {
async function deleteEvaluationPointsByGroupId(groupId: string, token?: string): Promise<{success: boolean; error?: string}> {
try {
const response = await postgrestDelete<ApiResponse<{id: number}>>('evaluation_points', {
filter: {
'evaluation_point_groups_id': `eq.${groupId}`
}
},
token
});
if (response.error) {
+9 -5
View File
@@ -100,6 +100,7 @@ export interface DocumentSearchParams {
sortOrder?: string; // 排序方式
page?: number; // 当前页码
pageSize?: number; // 每页条数
token?: string; // JWT token
}
@@ -168,7 +169,8 @@ export async function getReviewFiles(searchParams: DocumentSearchParams = {}, do
reviewStatus,
dateFrom,
dateTo,
sortOrder = 'upload_time_desc'
sortOrder = 'upload_time_desc',
token
} = searchParams;
let p_typeid: number[] | null = null;
@@ -204,8 +206,8 @@ export async function getReviewFiles(searchParams: DocumentSearchParams = {}, do
// 并行执行获取数据和获取总数的请求
const [filesResponse, countResponse] = await Promise.all([
postgrestPost<ReviewFileFromSQL[]>('rpc/get_review_files_with_details', listParams),
postgrestPost<number>('rpc/count_review_files', rpcParams)
postgrestPost<ReviewFileFromSQL[]>('rpc/get_review_files_with_details', listParams, token),
postgrestPost<number>('rpc/count_review_files', rpcParams, token)
]);
// 处理获取文档列表的错误
@@ -316,9 +318,10 @@ export async function getReviewFiles(searchParams: DocumentSearchParams = {}, do
* @param id 文件ID
* @param auditStatus 审核状态
* @param userId 用户ID
* @param token JWT token (可选)
* @returns 更新结果
*/
export async function updateDocumentAuditStatus(id: string, auditStatus: number, userId: string): Promise<{
export async function updateDocumentAuditStatus(id: string, auditStatus: number, userId: string, token?: string): Promise<{
success?: boolean;
error?: string;
status?: number;
@@ -338,7 +341,8 @@ export async function updateDocumentAuditStatus(id: string, auditStatus: number,
{
id: parseInt(id),
user_id: parseInt(userId) // 确保只能更新自己的文档
}
},
token
);
if (response.error) {
+39 -21
View File
@@ -35,6 +35,7 @@ export interface RulesQueryParams {
orderBy?: string;
orderDirection?: 'asc' | 'desc';
reviewType?: string; // 添加 reviewType 参数,值为 contract 或 record
token?: string; // JWT token
}
/**
@@ -164,7 +165,8 @@ export async function getRulesList(params: RulesQueryParams): Promise<{data: Rul
keyword,
orderBy = 'created_at',
orderDirection = 'desc',
reviewType
reviewType,
token
} = params;
// 构建PostgrestParams参数
@@ -194,7 +196,8 @@ export async function getRulesList(params: RulesQueryParams): Promise<{data: Rul
// 添加额外头部,用于获取总记录数
headers: {
'Prefer': 'count=exact'
}
},
token
};
// 添加精确匹配过滤:规则组ID
@@ -211,7 +214,8 @@ export async function getRulesList(params: RulesQueryParams): Promise<{data: Rul
try {
// 先获取所有评查点组数据,用于找到对应的pid
const groupsAllResponse = await postgrestGet<{code: number; msg: string; data: Array<{id: number; pid: number}>}>('evaluation_point_groups', {
select: 'id,pid'
select: 'id,pid',
token
});
let groups: Array<{id: number; pid: number}> = [];
@@ -254,7 +258,8 @@ export async function getRulesList(params: RulesQueryParams): Promise<{data: Rul
select: 'id',
filter: {
'pid': `eq.${ruleType}`
}
},
token
};
const groupsResponse = await postgrestGet<{code: number; msg: string; data: Array<{id: number}>}>('evaluation_point_groups', groupsParams);
@@ -364,7 +369,8 @@ export async function getRulesList(params: RulesQueryParams): Promise<{data: Rul
// 使用Promise.all并行查询所有分组信息 - 使用正确的函数名
const groupPromises = validGroupIds.map(id =>
postgrestGet<{code: number; msg: string; data: {id: number; pid: number; name: string; first_name: string; second_name: string}[]}>(
`rpc/get_evaluation_point_group_with_pid?input_id=${id}`
`rpc/get_evaluation_point_group_with_pid?input_id=${id}`,
{ token }
)
);
@@ -447,9 +453,10 @@ export async function getRulesList(params: RulesQueryParams): Promise<{data: Rul
/**
* 获取单个评查点详情
* @param id 评查点ID
* @param token JWT token (可选)
* @returns 评查点详情
*/
export async function getRule(id: string): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
export async function getRule(id: string, token?: string): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 使用postgrestGet获取单个评查点数据
const postgrestParams: PostgrestParams = {
@@ -473,7 +480,8 @@ export async function getRule(id: string): Promise<{data: Rule; error?: never} |
action_config,
created_at,
updated_at
`
`,
token
};
// 获取评查点详情
@@ -498,7 +506,8 @@ export async function getRule(id: string): Promise<{data: Rule; error?: never} |
select: 'id,name',
filter: {
'id': `eq.${apiRule.evaluation_point_groups_id}`
}
},
token
};
// 查询评查点分组
@@ -538,9 +547,10 @@ export async function getRule(id: string): Promise<{data: Rule; error?: never} |
/**
* 创建新评查点
* @param ruleData 评查点数据
* @param token JWT token (可选)
* @returns 创建的评查点
*/
export async function createRule(ruleData: Omit<Rule, 'id' | 'createdAt' | 'updatedAt'>): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
export async function createRule(ruleData: Omit<Rule, 'id' | 'createdAt' | 'updatedAt'>, token?: string): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 将前端模型转换为API接受的格式
const apiRuleData = {
@@ -569,7 +579,7 @@ export async function createRule(ruleData: Omit<Rule, 'id' | 'createdAt' | 'upda
};
// 使用postgrestPost创建评查点
const response = await postgrestPost<{code: number; msg: string; data: ApiRule}, typeof apiRuleData>('evaluation_points', apiRuleData);
const response = await postgrestPost<{code: number; msg: string; data: ApiRule}, typeof apiRuleData>('evaluation_points', apiRuleData, token);
// 检查是否有错误响应
if (response.error) {
@@ -598,9 +608,10 @@ export async function createRule(ruleData: Omit<Rule, 'id' | 'createdAt' | 'upda
* 更新评查点
* @param id 评查点ID
* @param ruleData 评查点数据
* @param token JWT token (可选)
* @returns 更新后的评查点
*/
export async function updateRule(id: string, ruleData: Partial<Omit<Rule, 'id' | 'createdAt' | 'updatedAt'>>): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
export async function updateRule(id: string, ruleData: Partial<Omit<Rule, 'id' | 'createdAt' | 'updatedAt'>>, token?: string): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 构建API接受的更新数据
const apiRuleData: Record<string, unknown> = {};
@@ -630,7 +641,7 @@ export async function updateRule(id: string, ruleData: Partial<Omit<Rule, 'id' |
}
// 使用postgrestPut更新评查点
const response = await postgrestPut<{code: number; msg: string; data: ApiRule}, typeof apiRuleData>(`evaluation_points/${id}`, apiRuleData);
const response = await postgrestPut<{code: number; msg: string; data: ApiRule}, typeof apiRuleData>(`evaluation_points/${id}`, apiRuleData, undefined, token);
// 检查是否有错误响应
if (response.error) {
@@ -658,9 +669,10 @@ export async function updateRule(id: string, ruleData: Partial<Omit<Rule, 'id' |
/**
* 删除评查点
* @param id 评查点ID
* @param token JWT token (可选)
* @returns 删除结果
*/
export async function deleteRule(id: string): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
export async function deleteRule(id: string, token?: string): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
try {
// console.log(`开始删除评查点, ID: ${id}`);
@@ -671,7 +683,8 @@ export async function deleteRule(id: string): Promise<{data: Rule; error?: never
},
headers: {
'Prefer': 'return=representation' // 请求返回被删除的记录
}
},
token
};
// 使用postgrestDelete删除评查点
@@ -771,12 +784,13 @@ export async function deleteRule(id: string): Promise<{data: Rule; error?: never
/**
* 复制评查点
* @param id 评查点ID
* @param token JWT token (可选)
* @returns 新创建的评查点
*/
export async function duplicateRule(id: string): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
export async function duplicateRule(id: string, token?: string): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 1. 获取原评查点详情
const ruleResponse = await getRule(id);
const ruleResponse = await getRule(id, token);
if (ruleResponse.error || !ruleResponse.data) {
return { error: ruleResponse.error || '获取评查点详情失败', status: 500 };
@@ -798,7 +812,7 @@ export async function duplicateRule(id: string): Promise<{data: Rule; error?: ne
};
// 3. 创建新评查点
return createRule(newRuleData);
return createRule(newRuleData, token);
} catch (error) {
console.error('复制评查点出错:', error);
@@ -833,9 +847,10 @@ export interface RuleGroup {
/**
* 获取评查点类型列表
* @param reviewType 评查类型,contract表示合同,record表示卷宗
* @param token JWT token (可选)
* @returns 评查点类型列表
*/
export async function getRuleTypes(reviewType?: string): Promise<{data: RuleType[]; error?: never} | {data?: never; error: string; status?: number}> {
export async function getRuleTypes(reviewType?: string, token?: string): Promise<{data: RuleType[]; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 构建PostgrestParams参数
const postgrestParams: PostgrestParams = {
@@ -850,7 +865,8 @@ export async function getRuleTypes(reviewType?: string): Promise<{data: RuleType
// 查询父ID为0的类型(顶级类型)
filter: {
'pid': 'eq.0'
}
},
token
};
// 根据 reviewType 添加过滤条件
@@ -919,9 +935,10 @@ export async function getRuleTypes(reviewType?: string): Promise<{data: RuleType
/**
* 根据评查点类型ID获取规则组列表
* @param typeId 评查点类型ID
* @param token JWT token (可选)
* @returns 规则组列表
*/
export async function getRuleGroupsByType(typeId: string): Promise<{data: RuleGroup[]; error?: never} | {data?: never; error: string; status?: number}> {
export async function getRuleGroupsByType(typeId: string, token?: string): Promise<{data: RuleGroup[]; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 如果typeId为空或为"全部",则返回空数组
if (!typeId || typeId === 'all') {
@@ -941,7 +958,8 @@ export async function getRuleGroupsByType(typeId: string): Promise<{data: RuleGr
// 查询指定类型ID的规则组
filter: {
'pid': `eq.${typeId}`
}
},
token
};
// 发送请求获取规则组列表
+29 -19
View File
@@ -39,6 +39,7 @@ export interface DocumentSearchParams {
pageSize?: number;
reviewType?: string;
userId?: string; // 添加用户ID筛选
token?: string; // JWT token
}
/**
@@ -88,6 +89,7 @@ export interface DocumentUI {
fileType: string;
path: string;
isTest: boolean;
remark?: string;
updatedAt?: string;
pageCount?: number;
ocrResult?: unknown;
@@ -108,11 +110,12 @@ function getFileExtension(filename: string): string {
* @param id 评查结果ID
* @returns 评查结果
*/
async function getEvaluationResults(id: number) {
async function getEvaluationResults(id: number, frontendJWT?: string) {
const response = await postgrestGet<[]>('evaluation_results', {
filter: {
'document_id': `eq.${id}`
}
},
token: frontendJWT
});
if (response.error) {
return { error: response.error, status: response.status };
@@ -125,12 +128,12 @@ async function getEvaluationResults(id: number) {
/**
* 将API文档转换为UI文档
*/
async function convertToUIDocument(doc: Document): Promise<DocumentUI> {
async function convertToUIDocument(doc: Document, frontendJWT?: string): Promise<DocumentUI> {
// 获取文档类型信息
const typeResponse = await getDocumentTypes();
const typeResponse = await getDocumentTypes(undefined, frontendJWT);
const documentTypes = typeResponse.data?.types || [];
const docType = documentTypes.find(type => type.id.toString() === doc.type_id.toString());
const evaluationResult = await getEvaluationResults(doc.id);
const evaluationResult = await getEvaluationResults(doc.id, frontendJWT);
let issues = 0;
interface EvaluationResultItem {
@@ -164,6 +167,7 @@ async function convertToUIDocument(doc: Document): Promise<DocumentUI> {
fileType: getFileExtension(doc.name),
path: doc.path,
isTest: doc.is_test_document,
remark: doc.remark,
updatedAt: formatDate(doc.updated_at),
pageCount: doc.ocr_result?.__meta?.page_count || 0,
ocrResult: doc.ocr_result
@@ -216,7 +220,8 @@ export async function getDocuments(searchParams: DocumentSearchParams = {}): Pro
dateFrom,
dateTo,
reviewType,
userId
userId,
token
} = searchParams;
let documentTypes: number[] | undefined;
@@ -248,8 +253,8 @@ export async function getDocuments(searchParams: DocumentSearchParams = {}): Pro
// 并行执行获取数据和获取总数的请求
const [documentsResponse, countResponse] = await Promise.all([
postgrestPost<DocumentFromSQL[], unknown>('rpc/get_documents_with_filters', { ...rpcParams, page, page_size: pageSize }),
postgrestPost<number, unknown>('rpc/count_documents_with_filters', rpcParams)
postgrestPost<DocumentFromSQL[], unknown>('rpc/get_documents_with_filters', { ...rpcParams, page, page_size: pageSize }, token),
postgrestPost<number, unknown>('rpc/count_documents_with_filters', rpcParams, token)
]);
// 处理获取文档列表的错误
@@ -305,9 +310,10 @@ export async function getDocuments(searchParams: DocumentSearchParams = {}): Pro
* 删除文档
* @param id 文档ID
* @param userId 用户ID
* @param token JWT token (可选)
* @returns 删除结果
*/
export async function deleteDocument(id: string, userId: string): Promise<{
export async function deleteDocument(id: string, userId: string, token?: string): Promise<{
success?: boolean;
error?: string;
status?: number;
@@ -327,7 +333,8 @@ export async function deleteDocument(id: string, userId: string): Promise<{
filter: {
'id': `eq.${id}`,
'user_id': `eq.${userId}` // 确保只能删除自己的文档
}
},
token
}
);
@@ -350,7 +357,7 @@ export async function deleteDocument(id: string, userId: string): Promise<{
* @param id 文档ID
* @returns 文档详情
*/
export async function getDocument(id: string, userId: string): Promise<{
export async function getDocument(id: string, userId: string, frontendJWT?: string): Promise<{
data?: DocumentUI;
error?: string;
status?: number;
@@ -371,7 +378,8 @@ export async function getDocument(id: string, userId: string): Promise<{
'id': `eq.${id}`,
'user_id': `eq.${userId}`
},
limit: 1
limit: 1,
token: frontendJWT
}
);
@@ -384,7 +392,7 @@ export async function getDocument(id: string, userId: string): Promise<{
return { error: '文档不存在', status: 404 };
}
const documentUI = await convertToUIDocument(extractedData[0]);
const documentUI = await convertToUIDocument(extractedData[0], frontendJWT);
return { data: documentUI };
} catch (error) {
@@ -402,7 +410,7 @@ export async function getDocument(id: string, userId: string): Promise<{
* @param id 文档ID
* @returns 文档详情
*/
export async function getDocumentWithNoUserId(id: string): Promise<{
export async function getDocumentWithNoUserId(id: string, frontendJWT?: string): Promise<{
data?: DocumentUI;
error?: string;
status?: number;
@@ -418,7 +426,8 @@ export async function getDocumentWithNoUserId(id: string): Promise<{
filter: {
'id': `eq.${id}`,
},
limit: 1
limit: 1,
token: frontendJWT
}
);
@@ -432,7 +441,7 @@ export async function getDocumentWithNoUserId(id: string): Promise<{
}
// console.log('extractedData', extractedData);
const documentUI = await convertToUIDocument(extractedData[0]);
const documentUI = await convertToUIDocument(extractedData[0], frontendJWT);
return { data: documentUI };
} catch (error) {
@@ -488,7 +497,7 @@ export async function getFileDownloadUrl(filePath: string): Promise<{
* @param document 部分文档数据
* @returns 更新结果
*/
export async function updateDocument(id: string, document: Partial<DocumentUI> & { remark?: string }, userId: string): Promise<{
export async function updateDocument(id: string, document: Partial<DocumentUI> & { remark?: string }, userId: string, frontendJWT?: string): Promise<{
data?: DocumentUI;
error?: string;
status?: number;
@@ -533,7 +542,8 @@ export async function updateDocument(id: string, document: Partial<DocumentUI> &
{
id: parseInt(id),
user_id: parseInt(userId) // 确保只能更新自己的文档
}
},
frontendJWT
);
if (response.error) {
@@ -542,7 +552,7 @@ export async function updateDocument(id: string, document: Partial<DocumentUI> &
}
// 获取更新后的完整文档数据
const updatedResponse = await getDocument(id, userId);
const updatedResponse = await getDocument(id, userId, frontendJWT);
return updatedResponse;
} catch (error) {
+22 -12
View File
@@ -357,12 +357,19 @@ export async function uploadDocumentToServer(
// const response = await fetch(`${API_BASE_URL}/admin/documents/upload`, {
try {
// console.log('【调试】开始fetch请求...');
// 构建请求头,只在有JWT token时添加Authorization
const headers: HeadersInit = {
'X-File-Name': encodeURIComponent(fileName)
};
if (jwtToken) {
headers['Authorization'] = `Bearer ${jwtToken}`;
}
const response = await fetch(uploadUrl, {
method: 'POST',
headers: {
'X-File-Name': encodeURIComponent(fileName),
'Authorization': `Bearer ${jwtToken || ''}`
},
headers,
body: formData
});
@@ -422,7 +429,7 @@ export async function uploadDocumentToServer(
* @param reviewType 审核类型(可选)
* @returns 文档列表
*/
export async function getTodayDocuments(userInfo?: { user_id?: number; [key: string]: unknown }, reviewType?: string): Promise<{data: Document[]; error?: never} | {data?: never; error: string; status?: number}> {
export async function getTodayDocuments(userInfo?: { user_id?: number; [key: string]: unknown }, reviewType?: string, token?: string): Promise<{data: Document[]; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 检查用户信息是否存在
if (!userInfo?.user_id) {
@@ -492,7 +499,7 @@ export async function getTodayDocuments(userInfo?: { user_id?: number; [key: str
// postgrestGet<ContractStructureComparison[]>('contract_structure_comparison', comparisonParams)
// ]);
const documentsResponse = await postgrestGet<Document[]>('documents', documentsParams);
const documentsResponse = await postgrestGet<Document[]>('documents', { ...documentsParams, token });
// console.log('documents表响应:', documentsResponse);
// console.log('contract_structure_comparison表响应:', comparisonResponse);
@@ -594,7 +601,7 @@ export async function getTodayDocuments(userInfo?: { user_id?: number; [key: str
}
// console.log('发送请求参数:', params);
const response = await postgrestGet<Document[]>('documents', params);
const response = await postgrestGet<Document[]>('documents', { ...params, token });
// console.log('API 响应:', response);
if (response.error) {
@@ -623,9 +630,10 @@ export async function getTodayDocuments(userInfo?: { user_id?: number; [key: str
/**
* 获取文档类型列表
* @param reviewType 审核类型(可选)
* @param token JWT token (可选)
* @returns 文档类型列表
*/
export async function getDocumentTypes(reviewType?: string): Promise<{data: DocumentType[]; error?: never} | {data?: never; error: string; status?: number}> {
export async function getDocumentTypes(reviewType?: string, token?: string): Promise<{data: DocumentType[]; error?: never} | {data?: never; error: string; status?: number}> {
try {
const params: PostgrestParams = {
select: 'id, name',
@@ -649,7 +657,7 @@ export async function getDocumentTypes(reviewType?: string): Promise<{data: Docu
}
}
const response = await postgrestGet<DocumentType[]>('document_types', params);
const response = await postgrestGet<DocumentType[]>('document_types', { ...params, token });
if (response.error) {
return { error: response.error, status: response.status };
@@ -674,11 +682,13 @@ export async function getDocumentTypes(reviewType?: string): Promise<{data: Docu
* 获取指定文档的状态
* @param documentIds 文档ID列表
* @param attachmentIds 合同附件ID列表(可选)
* @param token JWT token (可选)
* @returns 文档状态列表
*/
export async function getDocumentsStatus(
documentIds: number[],
attachmentIds?: number[]
attachmentIds?: number[],
token?: string
): Promise<{data: Document[]; error?: never} | {data?: never; error: string; status?: number}> {
try {
if ((!documentIds || documentIds.length === 0) && (!attachmentIds || attachmentIds.length === 0)) {
@@ -695,7 +705,7 @@ export async function getDocumentsStatus(
'id': `in.(${documentIds.join(',')})`
}
};
documentsResponse = await postgrestGet<Document[]>('documents', documentsParams);
documentsResponse = await postgrestGet<Document[]>('documents', { ...documentsParams, token });
}
// 查询合同附件状态
@@ -708,7 +718,7 @@ export async function getDocumentsStatus(
'id': `in.(${attachmentIds.join(',')})`
}
};
attachmentResponse = await postgrestGet<ContractStructureComparison[]>('contract_structure_comparison', attachmentParams);
attachmentResponse = await postgrestGet<ContractStructureComparison[]>('contract_structure_comparison', { ...attachmentParams, token });
}
if (documentsResponse.error && attachmentResponse.error) {
+12 -10
View File
@@ -94,9 +94,11 @@ function buildTypeFilter(reviewType: string | null): string {
/**
* 获取主页数据
* @param reviewType 从客户端传入的 reviewType 值
* @param userId 用户ID
* @param token JWT token
* @returns 主页数据
*/
export async function getHomeData(reviewType?: string | null,userId?: string | number): Promise<HomeStatistics> {
export async function getHomeData(reviewType?: string | null,userId?: string | number, token?: string): Promise<HomeStatistics> {
try {
// 获取当前日期和时间相关值
const startOfToday = dayjs().startOf('day').format('YYYY-MM-DD HH:mm:ss');
@@ -170,7 +172,7 @@ export async function getHomeData(reviewType?: string | null,userId?: string | n
}
const todayPendingCount = await handleApiResponse<{ count: number }[]>(
postgrestGet('documents', todayPendingParams),
postgrestGet('documents', { ...todayPendingParams, token }),
'获取今日待审核文件数量失败',
[]
);
@@ -201,7 +203,7 @@ export async function getHomeData(reviewType?: string | null,userId?: string | n
}
const thisMonthReviewedCount = await handleApiResponse<{ count: number }[]>(
postgrestGet('documents', thisMonthReviewedParams),
postgrestGet('documents', { ...thisMonthReviewedParams, token }),
'获取本月已审核文件数量失败',
[]
);
@@ -237,7 +239,7 @@ export async function getHomeData(reviewType?: string | null,userId?: string | n
}
const lastMonthReviewedCount = await handleApiResponse<{ count: number }[]>(
postgrestGet('documents', lastMonthReviewedParams),
postgrestGet('documents', { ...lastMonthReviewedParams, token }),
'获取上月已审核文件数量失败',
[]
);
@@ -283,7 +285,7 @@ export async function getHomeData(reviewType?: string | null,userId?: string | n
}
const thisMonthTotalCount = await handleApiResponse<{ count: number }[]>(
postgrestGet('documents', thisMonthTotalParams),
postgrestGet('documents', { ...thisMonthTotalParams, token }),
'获取本月审核通过数量失败',
[]
);
@@ -323,7 +325,7 @@ export async function getHomeData(reviewType?: string | null,userId?: string | n
}
const lastMonthTotalCount = await handleApiResponse<{ count: number }[]>(
postgrestGet('documents', lastMonthTotalParams),
postgrestGet('documents', { ...lastMonthTotalParams, token }),
'获取上月审核通过数量失败',
[]
);
@@ -373,7 +375,7 @@ export async function getHomeData(reviewType?: string | null,userId?: string | n
end_time: endOfThisMonth,
type_val: typeToQuery,
userid: parseInt(userId as string)
}),
}, token),
'获取合同本月问题数据失败',
[]
);
@@ -388,7 +390,7 @@ export async function getHomeData(reviewType?: string | null,userId?: string | n
end_time: endOfLastMonth,
type_val: typeToQuery,
userid: parseInt(userId as string)
}),
}, token),
'获取上月问题数据失败',
[]
);
@@ -406,7 +408,7 @@ export async function getHomeData(reviewType?: string | null,userId?: string | n
end_time: endOfThisMonth,
type_val: typeToQuery,
userid: parseInt(userId as string)
}),
}, token),
'获取本月许可卷宗类型2问题数据失败',
[]
);
@@ -422,7 +424,7 @@ export async function getHomeData(reviewType?: string | null,userId?: string | n
end_time: endOfLastMonth,
type_val: typeToQuery,
userid: parseInt(userId as string)
}),
}, token),
'获取上月许可卷宗类型2问题数据失败',
[]
);
+30
View File
@@ -0,0 +1,30 @@
// app/api/jwt-helper.server.ts
import { getUserSession } from './login/auth.server';
/**
* 从 request 中获取 JWT token
* @param request Remix Request 对象
* @returns JWT token 或 undefined
*/
export async function getJwtFromRequest(request: Request): Promise<string | undefined> {
const { frontendJWT } = await getUserSession(request);
return frontendJWT || undefined;
}
/**
* 包装 PostgrestParams,自动添加 JWT
* @param request Remix Request 对象
* @param params 原始参数
* @returns 包含 JWT 的参数
*/
export async function withJwt<T extends { token?: string }>(
request: Request,
params?: T
): Promise<T & { token: string | undefined }> {
const jwt = await getJwtFromRequest(request);
return {
...params as T,
token: jwt
};
}
+40 -16
View File
@@ -526,10 +526,10 @@ async function callIDaaSLogout(accessToken: string, appId: string): Promise<void
* @param userInfo - 从 IDaaS 获取的用户信息
* @returns Promise<{success: boolean, data?: SsoUser, error?: string}>
*/
export async function saveUserInfo(userInfo: UserInfo): Promise<{success: boolean, data?: SsoUser, error?: string}> {
export async function saveUserInfo(userInfo: UserInfo, token?: string): Promise<{success: boolean, data?: SsoUser, error?: string}> {
try {
console.log("开始保存用户信息", userInfo);
// 验证必要字段
if (!userInfo.sub) {
return { success: false, error: "用户唯一标识 sub 不能为空" };
@@ -540,7 +540,8 @@ export async function saveUserInfo(userInfo: UserInfo): Promise<{success: boolea
filter: {
"sub": `eq.${userInfo.sub}`,
"deleted_at": "is.null" // 只查询未删除的记录
}
},
token
});
if (existingUserResult.error) {
@@ -572,7 +573,8 @@ export async function saveUserInfo(userInfo: UserInfo): Promise<{success: boolea
const updateResult = await postgrestPut<SsoUser[], Partial<SsoUser>>(
"sso_users",
userData,
{ id: existingUser.id! }
{ id: existingUser.id! },
token
);
if (updateResult.error) {
@@ -589,7 +591,7 @@ export async function saveUserInfo(userInfo: UserInfo): Promise<{success: boolea
// 3. 用户不存在,执行插入操作 同时需要给这个用户默认添加一个角色,角色为common
console.log("用户不存在,执行插入操作");
const insertResult = await postgrestPost<SsoUser[], SsoUser>("sso_users", userData as SsoUser);
const insertResult = await postgrestPost<SsoUser[], SsoUser>("sso_users", userData as SsoUser, token);
if (insertResult.error) {
console.error("插入用户失败:", insertResult.error);
@@ -601,7 +603,7 @@ export async function saveUserInfo(userInfo: UserInfo): Promise<{success: boolea
// 4. 给这个用户默认添加一个角色,角色为common
const userData_with_id = Array.isArray(insertResult.data) ? insertResult.data[0] : insertResult.data as unknown as SsoUser;
if (userData_with_id?.id) {
await addDefaultRole(userData_with_id.id, 2);
await addDefaultRole(userData_with_id.id, 2, token);
}
return {
@@ -620,21 +622,23 @@ export async function saveUserInfo(userInfo: UserInfo): Promise<{success: boolea
/**
* 为用户添加默认角色
*
*
* @param userId - 用户ID
* @param roleId - 角色ID,默认为2common角色)
* @param token - JWT令牌,用于调用postgrest服务
* @returns 添加结果
*/
export async function addDefaultRole(userId: string, roleId: number = 2) {
export async function addDefaultRole(userId: string, roleId: number = 2, token?: string) {
try {
console.log(`为用户 ${userId} 添加默认角色 ${roleId}`);
// 检查用户是否已经有此角色
const existingRoleResult = await postgrestGet<Array<{id: number, user_id: string, role_id: number}>>("user_role", {
filter: {
user_id: `eq.${userId}`,
role_id: `eq.${roleId}`
}
},
token
});
if (existingRoleResult.error) {
@@ -652,7 +656,7 @@ export async function addDefaultRole(userId: string, roleId: number = 2) {
const addRoleResult = await postgrestPost<Array<{id: number, user_id: string, role_id: number}>, {user_id: string, role_id: number}>("user_role", {
user_id: userId,
role_id: roleId
});
}, token);
if (addRoleResult.error) {
console.error("添加用户角色失败:", addRoleResult.error);
@@ -749,11 +753,16 @@ export async function simpleRootLogin(
});
const loginResult = await loginResponse.json();
console.log('登录接口返回', loginResult);
// 检查重试次数
const retryCount = loginResult.retryCount || loginResult.retry_count || 0;
console.log('登录重试次数:', retryCount);
if (loginResult.code === 0 && loginResult.data) {
// 登录成功,构建用户信息
const userData = loginResult.data;
console.log('管理员登录userData', userData);
// console.log('管理员登录userData', userData);
const userRole = userData.role; // 默认角色
// 生成模拟的OAuth token信息
@@ -797,13 +806,28 @@ export async function simpleRootLogin(
frontendJWT
});
} else {
// 登录失败,返回错误信息
const errorMsg = loginResult.msg || "登录失败,请检查用户名和密码";
// 登录失败,检查账户是否被锁定
let errorMsg = loginResult.msg || "登录失败,请检查用户名和密码";
let isLocked = false;
// 检查是否因重试次数过多被锁定
if (retryCount >= 5) {
errorMsg = "账户已被锁定,密码错误次数过多,请联系管理员";
isLocked = true;
} else if (retryCount > 0) {
// 显示剩余尝试次数
const remainingAttempts = 5 - retryCount;
errorMsg = `${loginResult.msg || "用户名或密码错误"},还有 ${remainingAttempts} 次尝试机会`;
}
return new Response(JSON.stringify({
success: false,
error: errorMsg
error: errorMsg,
retryCount: retryCount,
isLocked: isLocked,
remainingAttempts: isLocked ? 0 : (5 - retryCount)
}), {
status: 401,
status: isLocked ? 403 : 401, // 403 表示禁止访问(账户被锁)
headers: { "Content-Type": "application/json" }
});
}
+4 -2
View File
@@ -6,7 +6,7 @@
* 2. 如果需要新的网络请求,在 `OAuthClient` 中添加
*/
import { OAuthClient } from "./oauth-client";
import { OAUTH_CONFIG } from "~/config/api-config";
import { getServerOAuthConfigRuntime } from "~/config/oauth-secret.server";
interface TokenInfo {
accessToken: string;
@@ -29,7 +29,9 @@ export class TokenManager {
private oauthClient: OAuthClient;
constructor() {
this.oauthClient = new OAuthClient(OAUTH_CONFIG);
// 🔒 安全:使用服务器端专用函数获取包含 clientSecret 的完整配置
// 从 .server.ts 文件中运行时读取,确保环境变量正确加载
this.oauthClient = new OAuthClient(getServerOAuthConfigRuntime());
}
/**
+98 -30
View File
@@ -1,7 +1,42 @@
// app/api/postgrest-client.ts
// import { AsyncLocalStorage } from 'async_hooks';
import { apiRequest, type QueryParams } from './axios-client';
import { handleApiError } from './error-handler';
/**
* 请求上下文接口
*/
// interface RequestContext {
// jwt?: string;
// }
/**
* 创建异步本地存储用于存储请求上下文
*/
// const requestContext = new AsyncLocalStorage<RequestContext>();
/**
* 在指定的上下文中运行函数
* @param context 上下文对象
* @param fn 要执行的函数
* @returns 函数执行结果
*/
// export function runWithContext<T>(
// context: RequestContext,
// fn: () => T | Promise<T>
// ): T | Promise<T> {
// return requestContext.run(context, fn);
// }
/**
* 获取当前上下文中的 JWT
* @returns JWT token 或 undefined
*/
// function getContextJWT(): string | undefined {
// const context = requestContext.getStore();
// return context?.jwt;
// }
/**
* PostgresREST 特定的查询参数接口
*/
@@ -23,6 +58,8 @@ export interface PostgrestParams {
[key: string]: unknown;
// 自定义头部参数
headers?: Record<string, string>;
// JWT Token(自动添加到 Authorization 头部)
token?: string;
}
/**
@@ -48,6 +85,38 @@ function decodeUrlForDisplay(url: string): string {
}
}
/**
* 合并 JWT Token 到请求头
* @param existingHeaders 已有的请求头
* @param explicitToken 显式传入的 JWT Token(可选)
* @returns 合并后的请求头
*/
function mergeAuthHeaders(
existingHeaders: Record<string, string> = {},
explicitToken?: string
): Record<string, string> {
const headers = { ...existingHeaders };
// 如果已经有 Authorization 头部(不区分大小写),不覆盖
const hasAuth = Object.keys(headers).some(
key => key.toLowerCase() === 'authorization'
);
if (hasAuth) {
return headers;
}
// 优先使用显式传入的 token,否则从上下文获取
const token = explicitToken || 'undefined';
// 如果有 token(显式传入或从上下文获取),添加到 Authorization 头部
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
return headers;
}
/**
* 打印 PostgREST 查询日志
* @param endpoint 端点
@@ -167,8 +236,8 @@ export function transformParams(params: PostgrestParams): QueryParams {
// 处理其他额外参数
Object.entries(params).forEach(([key, value]) => {
// 跳过已处理的特殊参数
if (!['select', 'order', 'limit', 'offset', 'filter', 'schema', 'or'].includes(key) && value !== undefined) {
// 跳过已处理的特殊参数(包括 headers 和 token
if (!['select', 'order', 'limit', 'offset', 'filter', 'schema', 'or', 'headers', 'token'].includes(key) && value !== undefined) {
result[key] = value as string | number | boolean;
}
});
@@ -179,7 +248,7 @@ export function transformParams(params: PostgrestParams): QueryParams {
/**
* 发送 GET 请求到 PostgresREST 接口
* @param endpoint 端点
* @param params 查询参数
* @param params 查询参数(可包含 token 和 headers
* @returns 响应数据
*/
export async function postgrestGet<T>(endpoint: string, params?: PostgrestParams): Promise<{data: T; headers?: Record<string, string>; error?: never} | {data?: never; error: string; status?: number}> {
@@ -191,13 +260,8 @@ export async function postgrestGet<T>(endpoint: string, params?: PostgrestParams
// 打印查询信息
logPostgrestQuery(apiEndpoint, queryParams, 'GET');
// 提取并移除自定义头部参数
const headers: Record<string, string> = params?.headers || {};
// 清除查询参数中的headers属性,避免将其作为URL参数
if (queryParams.headers) {
delete queryParams.headers;
}
// 合并 JWT Token 到请求头
const headers = mergeAuthHeaders(params?.headers, params?.token);
const response = await apiRequest<T>(
apiEndpoint,
@@ -215,7 +279,7 @@ export async function postgrestGet<T>(endpoint: string, params?: PostgrestParams
// 返回数据和响应头
return {
data: response.data as T,
headers: response.headers // 假设apiRequest函数已返回响应头
headers: response.headers
};
} catch (error) {
const apiError = handleApiError(error);
@@ -314,9 +378,10 @@ function handlePostgresError(error: unknown, responseText?: string): { message:
* 发送 POST 请求到 PostgresREST 接口
* @param endpoint 端点(表名)
* @param data 请求体数据
* @param token JWT Token(可选)
* @returns 响应数据
*/
export async function postgrestPost<T, D = Record<string, unknown>>(endpoint: string, data: D): Promise<{data: T; error?: never} | {data?: never; error: string; status?: number}> {
export async function postgrestPost<T, D = Record<string, unknown>>(endpoint: string, data: D, token?: string): Promise<{data: T; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 确保端点没有前导斜杠
const apiEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
@@ -332,17 +397,20 @@ export async function postgrestPost<T, D = Record<string, unknown>>(endpoint: st
// console.log(`准备发送 PostgreSQL 插入请求到: ${apiEndpoint}`);
// console.log(`请求体: ${requestBody}`);
// 合并 JWT Token 到请求头
const headers = mergeAuthHeaders({
'Content-Type': 'application/json',
'Accept': 'application/json',
'Prefer': 'return=representation'
}, token);
try {
const response = await apiRequest<T>(
apiEndpoint,
{
method: 'POST',
body: requestBody,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Prefer': 'return=representation'
}
headers: headers
}
);
@@ -434,12 +502,14 @@ function preprocessData(data: Record<string, unknown>): Record<string, unknown>
* @param endpoint 端点
* @param data 请求体数据
* @param filters 过滤条件
* @param token JWT Token(可选)
* @returns 响应数据
*/
export async function postgrestPut<T, D extends object>(
endpoint: string,
data: D,
filters?: Record<string | number, string | number>
filters?: Record<string | number, string | number>,
token?: string
): Promise<{data: T; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 确保端点没有前导斜杠
@@ -459,14 +529,17 @@ export async function postgrestPut<T, D extends object>(
// 打印查询信息
logPostgrestQuery(fullEndpoint, queryParams, 'PATCH', data as unknown as Record<string, unknown>);
// 合并 JWT Token 到请求头
const headers = mergeAuthHeaders({
'Prefer': 'return=representation'
}, token);
const response = await apiRequest<T>(
fullEndpoint,
{
method: 'PATCH',
body: JSON.stringify(data),
headers: {
'Prefer': 'return=representation'
}
headers: headers
},
queryParams
);
@@ -489,7 +562,7 @@ export async function postgrestPut<T, D extends object>(
/**
* 发送 DELETE 请求到 PostgresREST 接口
* @param endpoint 端点
* @param params 查询参数,用于指定要删除的记录
* @param params 查询参数,用于指定要删除的记录(可包含 token 和 headers
* @returns 响应数据
*/
export async function postgrestDelete<T>(endpoint: string, params?: PostgrestParams): Promise<{data: T; error?: never} | {data?: never; error: string; status?: number}> {
@@ -500,16 +573,11 @@ export async function postgrestDelete<T>(endpoint: string, params?: PostgrestPar
// 转换查询参数
const queryParams = params ? transformParams(params) : {};
// 提取并移除自定义头部参数
const headers: Record<string, string> = {
// 合并 JWT Token 到请求头
const headers = mergeAuthHeaders({
'Prefer': 'return=representation', // 默认请求返回被删除的记录
...(params?.headers || {})
};
// 清除查询参数中的headers属性,避免将其作为URL参数
if (queryParams.headers) {
delete queryParams.headers;
}
}, params?.token);
// 打印查询信息
logPostgrestQuery(apiEndpoint, queryParams, 'DELETE');
+20 -10
View File
@@ -113,9 +113,10 @@ export function convertToUITemplate(template: PromptTemplate): PromptTemplateUI
/**
* 获取提示词模板列表
* @param searchParams 搜索参数
* @param frontendJWT JWT token (可选)
* @returns 提示词模板列表和总数
*/
export async function getPromptTemplates(searchParams: PromptSearchParams = {}): Promise<{
export async function getPromptTemplates(searchParams: PromptSearchParams = {}, frontendJWT?: string): Promise<{
data?: { templates: PromptTemplateUI[], total: number };
error?: string;
status?: number;
@@ -147,7 +148,8 @@ export async function getPromptTemplates(searchParams: PromptSearchParams = {}):
},
limit: pageSize,
offset: (page - 1) * pageSize,
filter: {} as Record<string, string>
filter: {} as Record<string, string>,
token: frontendJWT
};
// 添加筛选条件
@@ -226,9 +228,10 @@ export async function getPromptTemplates(searchParams: PromptSearchParams = {}):
/**
* 获取提示词模板详情
* @param id 模板ID
* @param frontendJWT JWT token (可选)
* @returns 提示词模板详情
*/
export async function getPromptTemplate(id: string): Promise<{
export async function getPromptTemplate(id: string, frontendJWT?: string): Promise<{
data?: PromptTemplateUI;
error?: string;
status?: number;
@@ -254,7 +257,8 @@ export async function getPromptTemplate(id: string): Promise<{
`,
filter: {
'id': `eq.${id}`
}
},
token: frontendJWT
};
const response = await postgrestGet<PromptTemplate[]>('prompt_templates', params);
@@ -282,9 +286,10 @@ export async function getPromptTemplate(id: string): Promise<{
/**
* 创建提示词模板
* @param template 提示词模板数据
* @param frontendJWT JWT token (可选)
* @returns 创建的提示词模板
*/
export async function createPromptTemplate(template: Partial<PromptTemplateUI>): Promise<{
export async function createPromptTemplate(template: Partial<PromptTemplateUI>, frontendJWT?: string): Promise<{
data?: PromptTemplateUI;
error?: string;
status?: number;
@@ -326,7 +331,8 @@ export async function createPromptTemplate(template: Partial<PromptTemplateUI>):
const response = await postgrestPost<PromptTemplate, Partial<PromptTemplate>>(
'prompt_templates',
apiTemplate
apiTemplate,
frontendJWT
);
if (response.error) {
@@ -353,9 +359,10 @@ export async function createPromptTemplate(template: Partial<PromptTemplateUI>):
* 更新提示词模板
* @param id 模板ID
* @param template 提示词模板数据
* @param frontendJWT JWT token (可选)
* @returns 更新后的提示词模板
*/
export async function updatePromptTemplate(id: string, template: Partial<PromptTemplateUI>): Promise<{
export async function updatePromptTemplate(id: string, template: Partial<PromptTemplateUI>, frontendJWT?: string): Promise<{
data?: PromptTemplateUI;
error?: string;
status?: number;
@@ -416,7 +423,8 @@ export async function updatePromptTemplate(id: string, template: Partial<PromptT
const response = await postgrestPut<PromptTemplate, Partial<PromptTemplate>>(
'prompt_templates',
apiTemplate,
{ id }
{ id },
frontendJWT
);
if (response.error) {
@@ -442,9 +450,10 @@ export async function updatePromptTemplate(id: string, template: Partial<PromptT
/**
* 删除提示词模板
* @param id 模板ID
* @param frontendJWT JWT token (可选)
* @returns 成功或失败信息
*/
export async function deletePromptTemplate(id: string): Promise<{
export async function deletePromptTemplate(id: string, frontendJWT?: string): Promise<{
success?: boolean;
error?: string;
status?: number;
@@ -460,7 +469,8 @@ export async function deletePromptTemplate(id: string): Promise<{
{
filter: {
'id': `eq.${id}`
}
},
token: frontendJWT
}
);
+17 -13
View File
@@ -50,7 +50,7 @@ export async function getConfigLists(params: {
is_active?: boolean;
page?: number;
pageSize?: number;
}): Promise<{data: ConfigItem[]; total: number; error?: never} | {data?: never; error: string}> {
}, token?: string): Promise<{data: ConfigItem[]; total: number; error?: never} | {data?: never; error: string}> {
try {
const {
name,
@@ -90,7 +90,7 @@ export async function getConfigLists(params: {
queryParams.filter = filter;
// 获取数据
const response = await postgrestGet<ConfigItem[]>('configurations', queryParams);
const response = await postgrestGet<ConfigItem[]>('configurations', { ...queryParams, token });
if (response.error) {
return { error: response.error };
@@ -132,11 +132,12 @@ export async function getConfigLists(params: {
}
// 获取配置类型和环境选项
export async function getConfigOptions(): Promise<{data: {types: string[]; environments: string[]}; error?: never} | {data?: never; error: string}> {
export async function getConfigOptions(token?: string): Promise<{data: {types: string[]; environments: string[]}; error?: never} | {data?: never; error: string}> {
try {
// 获取类型选项
const typeResponse = await postgrestGet<{type: string}[]>('configurations', {
select: 'type'
select: 'type',
token
});
if (typeResponse.error) {
@@ -150,7 +151,8 @@ export async function getConfigOptions(): Promise<{data: {types: string[]; envir
// 获取环境选项
const envResponse = await postgrestGet<{environment: string}[]>('configurations', {
select: 'environment'
select: 'environment',
token
});
if (envResponse.error) {
@@ -179,12 +181,13 @@ export async function getConfigOptions(): Promise<{data: {types: string[]; envir
}
// 获取配置详情
export async function getConfigDetail(id: string): Promise<{data: ConfigItem; error?: never} | {data?: never; error: string}> {
export async function getConfigDetail(id: string, token?: string): Promise<{data: ConfigItem; error?: never} | {data?: never; error: string}> {
try {
const response = await postgrestGet<ConfigItem[]>('configurations', {
filter: {
'id': `eq.${id}`
}
},
token
});
if (response.error) {
@@ -218,9 +221,9 @@ export async function createConfig(data: {
config: Record<string, unknown>;
is_active: boolean;
remark?: string;
}): Promise<{data: ConfigItem; error?: never} | {data?: never; error: string}> {
}, token?: string): Promise<{data: ConfigItem; error?: never} | {data?: never; error: string}> {
try {
const response = await postgrestPost<ConfigItem, typeof data>('configurations', data);
const response = await postgrestPost<ConfigItem, typeof data>('configurations', data, token);
if (response.error) {
return { error: response.error };
@@ -252,11 +255,11 @@ export async function updateConfig(id: string, data: {
config: Record<string, unknown>;
is_active: boolean;
remark?: string;
}): Promise<{data: ConfigItem; error?: never} | {data?: never; error: string}> {
}, token?: string): Promise<{data: ConfigItem; error?: never} | {data?: never; error: string}> {
try {
const response = await postgrestPut<ConfigItem, typeof data>('configurations', data, {
id: id.toString()
});
}, token);
if (response.error) {
return { error: response.error };
@@ -281,12 +284,13 @@ export async function updateConfig(id: string, data: {
}
// 更新配置状态
export async function updateConfigStatus(id: number, is_active: boolean): Promise<{success: boolean; error?: string}> {
export async function updateConfigStatus(id: number, is_active: boolean, token?: string): Promise<{success: boolean; error?: string}> {
try {
const response = await postgrestPut<ConfigItem, {is_active: boolean}>(
'configurations',
{ is_active },
{ id: id.toString() }
{ id: id.toString() },
token
);
if (response.error) {