fix: 1. 重新对齐交叉评查的接口。

2. 确认评查结果的接口对接。 3. 新增评查点适配省级创建的响应数据和其他用户创建的单条响应数据。  4. 文档列表的文档类型通过通用的查询接口查询文档类型。优化加载状态的时机。
This commit is contained in:
2025-12-11 11:16:50 +08:00
parent ba517d7b9c
commit d8bba607fc
18 changed files with 3435 additions and 1086 deletions
+217 -146
View File
@@ -1,5 +1,5 @@
import { postgrestGet, type PostgrestParams, postgrestPut, postgrestPost } from "../postgrest-client";
import {getDocumentWithNoUserId} from "~/api/files/documents";
// import {getDocumentWithNoUserId} from "~/api/files/documents";
import dayjs from "dayjs";
import { getUserSession } from "~/api/login/auth.server";
import { apiRequest } from "../axios-client";
@@ -124,13 +124,13 @@ interface ScoringProposal {
document_id: string | number;
}
/**
* 获取当前评查文件的所有评查点结果
/** ============== (废弃,已经采用api接口的方式进行查询)
* 获取当前评查文件的所有评查点结果
* @param fileId 评查文件ID
* @param request Remix请求对象,用于获取用户会话
* @returns 评查点结果列表和统计数据
*/
export async function getReviewPoints(fileId: string, request: Request) {
export async function getReviewPoints(fileId: string, request: Request) {
// 获取用户会话信息
const { userInfo, frontendJWT } = await getUserSession(request);
@@ -744,17 +744,27 @@ export async function getReviewPoints(fileId: string, request: Request) {
* 更新评查结果
* @param resultId 评查结果ID
* @param editAuditStatusId 审核状态ID
* @param result 评查结果 (true/false)
* @param result 评查结果 (true/false/review)
* @param message 评查意见
* @param request Remix请求对象,用于获取用户会话
* @param documentId 文档ID(可选,用于创建新审核状态)
* @param evaluationPointId 评查点ID(可选,用于创建新审核状态)
* @returns 更新后的评查结果
*
* 🔥 接口文档: auth_doc/评查审核接口对接文档.md
* 📍 使用接口:
* - 3.1 更新评查结果: PATCH /admin/v2/evaluations/results/{result_id}
* - 3.2 创建审核状态: POST /admin/v2/evaluations/audit-status
* - 3.3 更新审核状态: PATCH /admin/v2/evaluations/audit-status/{audit_status_id}
*/
export async function updateReviewResult(
resultId: string,
editAuditStatusId: string | number,
result: string,
resultId: string,
editAuditStatusId: string | number,
result: string,
message: string,
request: Request
request: Request,
documentId?: string | number,
evaluationPointId?: string | number
): Promise<{
data?: unknown;
error?: string;
@@ -763,122 +773,184 @@ export async function updateReviewResult(
try {
// 获取用户会话信息
const { userInfo, frontendJWT } = await getUserSession(request);
if (!userInfo?.user_id) {
console.error("用户身份验证失败");
return { error: '用户身份验证失败', status: 401 };
}
const userId = userInfo.user_id;
if (!resultId) {
return { error: '评查结果ID不能为空', status: 400 };
}
// 首先获取当前评查结果数据
const currentResultResponse = await postgrestGet('/api/postgrest/proxy/evaluation_results', {
select: '*',
filter: { id: `eq.${resultId}` },
token: frontendJWT
});
console.log('/api/postgrest/proxy/evaluation_results',currentResultResponse.error)
if (currentResultResponse.error) {
return { error: currentResultResponse.error, status: currentResultResponse.status };
}
const currentResultData = extractApiData<EvaluationResult[]>(currentResultResponse.data);
if (!currentResultData || !Array.isArray(currentResultData) || currentResultData.length === 0) {
return { error: '未找到评查结果数据', status: 404 };
}
const currentResult = currentResultData[0];
const currentEvaluatedResults = currentResult.evaluated_results || {};
// 判断是否是重新审核操作
const isReview = result === 'review';
// console.log('isReview-------', result);
// 构建要更新的数据,保留原有字段
const updatedEvaluatedResults = {
...currentEvaluatedResults,
// 如果是重新审核操作,不更新result和message
...(isReview ? {} : { result: result === 'true' ? true : false, message }),
};
const updatedData = {
evaluated_results: updatedEvaluatedResults
};
// 调用 API 更新评查点结果数据
const resultResponse = await postgrestPut<unknown, typeof updatedData>(
'/api/postgrest/proxy/evaluation_results',
updatedData,
{ id: resultId },
frontendJWT
);
if (resultResponse.error) {
return { error: resultResponse.error, status: resultResponse.status };
// ============================================
// 步骤1: 调用3.1接口更新评查结果(如果不是重新审核操作)
// ============================================
if (!isReview) {
// 构建请求数据
const updateResultData: {
result?: 'true' | 'false';
message?: string;
} = {
result: result === 'true' ? 'true' : 'false',
message: message
};
// 调用 3.1 接口: PATCH /admin/v2/evaluations/results/{result_id}
const resultResponse = await apiRequest<{
success: boolean;
message: string;
data: {
result_id: number;
updated_fields: string[];
};
}>(
`/admin/v2/evaluations/results/${resultId}`,
{
method: 'PATCH',
headers: {
'Authorization': `Bearer ${frontendJWT}`,
'Content-Type': 'application/json'
},
data: updateResultData
}
);
if (resultResponse.error) {
console.error('❌ [updateReviewResult] 3.1接口调用失败:', resultResponse.error);
return { error: resultResponse.error, status: resultResponse.status || 500 };
}
if (!resultResponse.data?.success) {
console.error('❌ [updateReviewResult] 3.1接口响应异常:', resultResponse.data);
return { error: resultResponse.data?.message || '更新评查结果失败', status: 500 };
}
}
// 处理audit_status表的更新或新增
// ============================================
// 步骤2: 处理审核状态(创建或更新)
// ============================================
// 确定edit_audit_status的值:
// 如果是重新审核操作,值为0;否则值为1
const editAuditStatusValue = isReview ? 0 : 1;
// console.log('editAuditStatusValue-------', editAuditStatusValue);
// console.log('editAuditStatusId-------', editAuditStatusId);
if (editAuditStatusId && editAuditStatusId !== '') {
// 更新现有审核状态记录
const auditStatusResponse = await postgrestPut(
'/api/postgrest/proxy/audit_status',
{
edit_audit_status: editAuditStatusValue,
// 重新审核时不更新message
...(isReview ? {} : { message })
},
{
id: editAuditStatusId,
user_id: userId // 添加用户ID条件,确保只能更新自己的记录
},
frontendJWT
// ============================================
// 使用3.3接口更新现有审核状态记录
// PATCH /admin/v2/evaluations/audit-status/{audit_status_id}
// ============================================
const updateAuditData: {
edit_audit_status: number;
message?: string;
} = {
edit_audit_status: editAuditStatusValue
};
// 重新审核时不更新message
if (!isReview) {
updateAuditData.message = message;
}
const auditStatusResponse = await apiRequest<{
success: boolean;
message: string;
data: {
audit_status_id: number;
updated_fields: string[];
};
}>(
`/admin/v2/evaluations/audit-status/${editAuditStatusId}`,
{
method: 'PATCH',
headers: {
'Authorization': `Bearer ${frontendJWT}`,
'Content-Type': 'application/json'
},
data: updateAuditData
}
);
if (auditStatusResponse.error) {
console.error('❌ [updateReviewResult] 3.3接口调用失败:', auditStatusResponse.error);
return { error: auditStatusResponse.error, status: auditStatusResponse.status || 500 };
}
} else {
// 如果没有editAuditStatusId,则创建新记录
// 首先获取文档ID和评查点ID
const documentId = currentResult.document_id;
const evaluationPointId = currentResult.evaluation_point_id;
// 创建新的审核状态记录
const newAuditStatus = {
document_id: documentId,
evaluation_point_id: evaluationPointId,
evaluation_result_id: resultId,
edit_audit_status: editAuditStatusValue,
message: isReview ? '' : message,
user_id: userId // 添加用户ID
};
// 使用postgrestPost创建新记录
const postResponse = await postgrestPost('/api/postgrest/proxy/audit_status', newAuditStatus, frontendJWT);
if (postResponse.error) {
return { error: postResponse.error, status: postResponse.status || 500 };
if (!auditStatusResponse.data?.success) {
console.error('❌ [updateReviewResult] 3.3接口响应异常:', auditStatusResponse.data);
return { error: auditStatusResponse.data?.message || '更新审核状态失败', status: 500 };
}
return { data: auditStatusResponse.data };
} else {
// ============================================
// 使用3.2接口创建新审核状态记录
// POST /admin/v2/evaluations/audit-status
// ============================================
// 如果没有传入documentId和evaluationPointId,需要先获取
if (!documentId || !evaluationPointId) {
// 从评查结果中获取document_id和evaluation_point_id
const currentResultResponse = await postgrestGet('/api/postgrest/proxy/evaluation_results', {
select: 'document_id,evaluation_point_id',
filter: { id: `eq.${resultId}` },
token: frontendJWT
});
if (currentResultResponse.error) {
return { error: currentResultResponse.error, status: currentResultResponse.status };
}
const currentResultData = extractApiData<EvaluationResult[]>(currentResultResponse.data);
if (!currentResultData || !Array.isArray(currentResultData) || currentResultData.length === 0) {
return { error: '未找到评查结果数据', status: 404 };
}
documentId = currentResultData[0].document_id;
evaluationPointId = currentResultData[0].evaluation_point_id;
}
// 创建新的审核状态记录
const newAuditStatusData = {
document_id: Number(documentId),
evaluation_point_id: Number(evaluationPointId),
evaluation_result_id: Number(resultId),
edit_audit_status: editAuditStatusValue,
message: isReview ? '' : message
};
const createAuditResponse = await apiRequest<{
id: number;
user_id: number;
document_id: number;
evaluation_point_id: number;
evaluation_result_id: number;
edit_audit_status: number;
message: string;
created_at: string;
updated_at: string;
}>(
`/admin/v2/evaluations/audit-status`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${frontendJWT}`,
'Content-Type': 'application/json'
},
data: newAuditStatusData
}
);
if (createAuditResponse.error) {
console.error('❌ [updateReviewResult] 3.2接口调用失败:', createAuditResponse.error);
return { error: createAuditResponse.error, status: createAuditResponse.status || 500 };
}
return { data: createAuditResponse.data };
}
const extractedData = extractApiData<unknown>(resultResponse.data);
if (!extractedData) {
return { error: '更新评查结果失败', status: 500 };
}
return { data: extractedData };
} catch (error) {
console.error('更新评查结果失败:', error);
return {
@@ -893,6 +965,9 @@ export async function updateReviewResult(
* @param documentId 文档ID
* @param request Remix请求对象,用于获取用户会话
* @returns 更新结果
*
* 🔥 接口文档: auth_doc/评查审核接口对接文档.md 3.4
* 📍 API地址: PATCH /admin/v2/evaluation/documents/{document_id}/confirm
*/
export async function confirmReviewResults(documentId: string, request: Request): Promise<{
data?: { auditStatus: number; };
@@ -902,57 +977,53 @@ export async function confirmReviewResults(documentId: string, request: Request)
try {
// 获取用户会话信息
const { userInfo, frontendJWT } = await getUserSession(request);
if (!userInfo?.user_id) {
console.error("用户身份验证失败");
return { error: '用户身份验证失败', status: 401 };
}
const userId = userInfo.user_id;
if (!documentId) {
return { error: '文档ID不能为空', status: 400 };
}
// 获取该文档的所有评查点结果
// const reviewPointsResponse = await getReviewPoints(documentId);
// if ('error' in reviewPointsResponse && reviewPointsResponse.error) {
// return { error: reviewPointsResponse.error, status: reviewPointsResponse.status };
// }
// if (!('data' in reviewPointsResponse) || !reviewPointsResponse.data || !Array.isArray(reviewPointsResponse.data)) {
// return { error: '获取评查点数据失败', status: 500 };
// }
// // 计算总分数
// const totalScore = reviewPointsResponse.stats?.score || 0;
// // 根据总分确定审核状态
// // <80分:不通过(-1),>=80分:通过(1)
// const auditStatus = totalScore < 80 ? -1 : 1;
// 更新文档的审核状态
const updateDocumentParams = {
audit_status: 1
};
// 调用API更新文档审核状态
const response = await postgrestPut<{ id: string }, typeof updateDocumentParams>(
'/api/postgrest/proxy/documents',
updateDocumentParams,
{
id: documentId,
user_id: userId // 添加用户ID条件,确保只能更新自己的文档
},
frontendJWT
// 调用后端API确认文档审核完成
// 接口: PATCH /admin/v2/evaluations/documents/{document_id}/confirm
const response = await apiRequest<{
success: boolean;
message: string;
data: {
document_id: number;
audit_status: number;
};
}>(
`/admin/v2/evaluations/documents/${documentId}/confirm`,
{
method: 'PATCH',
headers: {
'Authorization': `Bearer ${frontendJWT}`,
'Content-Type': 'application/json'
},
data: {
audit_status: 1
}
}
);
// 处理错误响应
if (response.error) {
return { error: response.error, status: response.status };
console.error('❌ [confirmReviewResults] API调用失败:', response.error);
return { error: response.error, status: response.status || 500 };
}
return { data: { auditStatus: 1} };
// 成功响应
if (response.data?.success) {
return { data: { auditStatus: response.data.data?.audit_status || 1 } };
}
// 数据为空或格式不正确
console.error('❌ [confirmReviewResults] API响应数据异常:', response.data);
return { error: response.data?.message || '确认文档审核失败', status: 500 };
} catch (error) {
console.error('确认评查结果失败:', error);
return {
+1 -754
View File
@@ -434,254 +434,7 @@ export async function getRule(id: string, token?: string): Promise<{data: Rule;
}
}
/**
* 创建新评查点
* @param ruleData 评查点数据
* @param token JWT token (可选)
* @returns 创建的评查点
*/
export async function createRule(ruleData: Omit<Rule, 'id' | 'createdAt' | 'updatedAt'>, token?: string): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 1. 验证必填字段
if (!ruleData.name || !ruleData.code) {
return { error: '评查点名称和编码不能为空', status: 400 };
}
// 2. 验证名称长度(1-100字符)
const trimmedName = ruleData.name.trim();
if (trimmedName.length === 0 || trimmedName.length > 100) {
return { error: '评查点名称长度必须在1-100个字符之间', status: 400 };
}
// 3. 验证编码格式(仅允许字母、数字、连字符和下划线)
const trimmedCode = ruleData.code.trim();
if (!/^[a-zA-Z0-9-_]+$/.test(trimmedCode)) {
return { error: '评查点编码只能包含字母、数字、连字符和下划线', status: 400 };
}
// 4. 验证编码唯一性
const existingRulesResponse = await getRulesList({
keyword: trimmedCode,
pageSize: 10,
token
});
if (existingRulesResponse.data && existingRulesResponse.data.rules.length > 0) {
// 精确匹配检查(因为keyword是模糊搜索)
const exactMatch = existingRulesResponse.data.rules.some(r => r.code === trimmedCode);
if (exactMatch) {
return { error: '评查点编码已存在,请使用其他编码', status: 409 };
}
}
// 5. 验证分组ID有效性
if (!ruleData.groupId) {
return { error: '必须选择所属规则组', status: 400 };
}
// 检查分组是否存在
const groupResponse = await postgrestGet<{code: number; msg: string; data: Array<{id: number; name: string; pid: number}> }>('/api/postgrest/proxy/evaluation_point_groups', {
filter: { 'id': `eq.${ruleData.groupId}` },
select: 'id,name,pid',
token
});
let groupExists = false;
if (groupResponse.data && 'code' in groupResponse.data && groupResponse.data.data) {
groupExists = Array.isArray(groupResponse.data.data) && groupResponse.data.data.length > 0;
} else if (Array.isArray(groupResponse.data)) {
groupExists = groupResponse.data.length > 0;
}
if (!groupExists) {
return { error: '所选规则组不存在', status: 404 };
}
// 将前端模型转换为API接受的格式
const apiRuleData = {
code: trimmedCode,
name: trimmedName,
evaluation_point_groups_id: parseInt(ruleData.groupId),
risk: ruleData.priority === 'high' ? '高' : ruleData.priority === 'medium' ? '中' : '低',
description: ruleData.description || '',
is_enabled: ruleData.isActive !== undefined ? ruleData.isActive : true,
// 以下是默认值,实际应用中需要根据业务逻辑设置
references_laws: {},
extraction_config: {
type: "OCR+LLM",
fields: []
},
evaluation_config: {
rules: [],
logicType: "and"
},
pass_message: "",
fail_message: "",
suggestion_message: "",
suggestion_message_type: "warning",
post_action: "none",
action_config: ""
};
// 使用postgrestPost创建评查点
const response = await postgrestPost<{code: number; msg: string; data: ApiRule}, typeof apiRuleData>('/api/postgrest/proxy/evaluation_points', apiRuleData, token);
// 检查是否有错误响应
if (response.error) {
return { error: response.error, status: response.status };
}
// 确保响应数据存在且符合预期格式
if (!response.data || !response.data.data) {
return { error: '接口返回数据格式不正确', status: 500 };
}
// 将API返回的数据映射到前端模型
const rule = mapApiRuleToFrontendModel(response.data.data);
return { data: rule };
} catch (error) {
console.error('创建评查点出错:', error);
return {
error: error instanceof Error ? error.message : '创建评查点失败',
status: 500
};
}
}
/**
* 更新评查点
* @param id 评查点ID
* @param ruleData 评查点数据
* @param token JWT token (可选)
* @returns 更新后的评查点
*/
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 {
// 1. 验证评查点ID有效性
const existingRuleResponse = await getRule(id, token);
if (existingRuleResponse.error || !existingRuleResponse.data) {
return { error: '评查点不存在', status: 404 };
}
// 2. 验证名称长度(如果提供)
if (ruleData.name !== undefined) {
const trimmedName = ruleData.name.trim();
if (trimmedName.length === 0 || trimmedName.length > 100) {
return { error: '评查点名称长度必须在1-100个字符之间', status: 400 };
}
}
// 3. 验证编码格式和唯一性(如果提供)
if (ruleData.code !== undefined) {
const trimmedCode = ruleData.code.trim();
// 验证编码格式
if (!/^[a-zA-Z0-9-_]+$/.test(trimmedCode)) {
return { error: '评查点编码只能包含字母、数字、连字符和下划线', status: 400 };
}
// 验证编码唯一性(排除自身)
const existingRulesResponse = await getRulesList({
keyword: trimmedCode,
pageSize: 10,
token
});
if (existingRulesResponse.data && existingRulesResponse.data.rules.length > 0) {
// 精确匹配检查,排除当前评查点自身
const exactMatch = existingRulesResponse.data.rules.some(r => r.code === trimmedCode && r.id !== id);
if (exactMatch) {
return { error: '评查点编码已被其他评查点使用', status: 409 };
}
}
}
// 4. 验证分组ID有效性(如果提供)
if (ruleData.groupId !== undefined) {
const groupResponse = await postgrestGet<{code: number; msg: string; data: Array<{id: number; name: string; pid: number}> }>('/api/postgrest/proxy/evaluation_point_groups', {
filter: { 'id': `eq.${ruleData.groupId}` },
select: 'id,name,pid',
token
});
let groupExists = false;
if (groupResponse.data && 'code' in groupResponse.data && groupResponse.data.data) {
groupExists = Array.isArray(groupResponse.data.data) && groupResponse.data.data.length > 0;
} else if (Array.isArray(groupResponse.data)) {
groupExists = groupResponse.data.length > 0;
}
if (!groupExists) {
return { error: '所选规则组不存在', status: 404 };
}
}
// 构建API接受的更新数据
const apiRuleData: Record<string, unknown> = {};
if (ruleData.code !== undefined) {
apiRuleData.code = ruleData.code.trim();
}
if (ruleData.name !== undefined) {
apiRuleData.name = ruleData.name.trim();
}
if (ruleData.groupId !== undefined) {
apiRuleData.evaluation_point_groups_id = parseInt(ruleData.groupId);
}
if (ruleData.priority !== undefined) {
apiRuleData.risk = ruleData.priority === 'high' ? '高' : ruleData.priority === 'medium' ? '中' : '低';
}
if (ruleData.description !== undefined) {
apiRuleData.description = ruleData.description;
}
if (ruleData.isActive !== undefined) {
apiRuleData.is_enabled = ruleData.isActive;
}
// 使用postgrestPut更新评查点 - 使用正确的PostgREST格式
const response = await postgrestPut<{code: number; msg: string; data: ApiRule} | ApiRule[], typeof apiRuleData>('/api/postgrest/proxy/evaluation_points', apiRuleData, { id: parseInt(id) }, token);
// 检查是否有错误响应
if (response.error) {
return { error: response.error, status: response.status };
}
// 处理响应数据(PostgREST可能返回数组或包装对象)
let updatedRule: ApiRule | null = null;
if (response.data) {
// 如果是数组格式(PostgREST标准响应)
if (Array.isArray(response.data)) {
updatedRule = response.data.length > 0 ? response.data[0] : null;
}
// 如果是包装对象格式
else if ('data' in response.data && response.data.data) {
updatedRule = response.data.data as ApiRule;
}
}
if (!updatedRule) {
return { error: '更新成功但无法获取更新后的数据', status: 500 };
}
// 将API返回的数据映射到前端模型
const rule = mapApiRuleToFrontendModel(updatedRule);
return { data: rule };
} catch (error) {
console.error('更新评查点出错:', error);
return {
error: error instanceof Error ? error.message : '更新评查点失败',
status: 500
};
}
}
/**
* 删除评查点
@@ -722,47 +475,7 @@ export async function deleteRule(id: string, token?: string): Promise<{data: {su
}
}
/**
* 复制评查点
* @param id 评查点ID
* @param token JWT token (可选)
* @returns 新创建的评查点
*/
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, token);
if (ruleResponse.error || !ruleResponse.data) {
return { error: ruleResponse.error || '获取评查点详情失败', status: 500 };
}
// 2. 准备新评查点数据
const rule = ruleResponse.data;
// 创建新评查点对象
const newRuleData = {
code: `${rule.code}-COPY`,
name: `${rule.name} (复制)`,
ruleType: rule.ruleType,
groupId: rule.groupId,
groupName: rule.groupName,
priority: rule.priority,
description: rule.description,
isActive: rule.isActive
};
// 3. 创建新评查点
return createRule(newRuleData, token);
} catch (error) {
console.error('复制评查点出错:', error);
return {
error: error instanceof Error ? error.message : '复制评查点失败',
status: 500
};
}
}
/**
* 评查点类型
@@ -1143,137 +856,6 @@ export function convertApiRuleToFormData(apiRule: ApiRule): FormattedEvaluationP
return formattedData;
}
/**
* 获取单个评查点数据
* @param id 评查点ID
* @returns 评查点数据
*/
/**
* 获取格式化的评查点数据(用于列表视图)
* @param id 评查点ID
* @returns 格式化的评查点数据
*/
export async function getFormattedEvaluationPoint(id: number): Promise<{
data?: FormattedEvaluationPoint;
error?: string;
status?: number;
}> {
try {
// console.log(`获取评查点数据,ID: ${id}`);
// 使用 postgrestGet 替代直接调用 fetch
const postgrestParams: PostgrestParams = {
select: `*`,
filter: {
'id': `eq.${id}`
}
};
const response = await postgrestGet<{code: number; msg: string; data: ApiRule[]} | ApiRule[]>('/api/postgrest/proxy/evaluation_points', postgrestParams);
if (response.error) {
return {
error: response.error,
status: response.status
};
}
// 使用 extractApiData 统一处理响应数据
const extractedData = extractApiData<ApiRule[]>(response.data);
if (extractedData && Array.isArray(extractedData) && extractedData.length > 0) {
// 转换数据为前端格式
const formattedData = convertApiRuleToFormData(extractedData[0]);
return { data: formattedData };
} else {
return {
error: '获取数据失败: 返回数据为空',
status: 404
};
}
} catch (error) {
console.error('获取评查点数据失败:', error);
return {
error: error instanceof Error ? error.message : '获取评查点数据失败',
status: 500
};
}
}
/**
* 获取评查点组数据
* @returns 评查点组列表
*/
export async function getEvaluationPointGroups(): Promise<{
data?: Array<{
id: number;
pid: number;
code: string;
name: string;
description: string;
is_enabled: boolean;
created_at: string;
updated_at: string;
}>;
error?: string;
status?: number;
}> {
try {
// console.log("获取评查点组数据");
// 使用 postgrestGet 替代直接调用 fetch
const postgrestParams: PostgrestParams = {
select: `*`
};
// 定义评查点组类型
type EvaluationPointGroupType = {
id: number;
pid: number;
code: string;
name: string;
description: string;
is_enabled: boolean;
created_at?: string;
updated_at?: string;
};
const response = await postgrestGet<{code: number; msg: string; data: EvaluationPointGroupType[]} | EvaluationPointGroupType[]>('/api/postgrest/proxy/evaluation_point_groups', postgrestParams);
if (response.error) {
return {
error: response.error,
status: response.status
};
}
// 使用 extractApiData 统一处理响应数据
const extractedData = extractApiData<EvaluationPointGroupType[]>(response.data);
if (extractedData) {
// 确保每个组都有 created_at 和 updated_at 字段
const currentTime = new Date().toISOString();
const formattedGroups = extractedData.map(group => ({
...group,
created_at: group.created_at || currentTime,
updated_at: group.updated_at || currentTime
}));
return { data: formattedGroups };
} else {
return {
error: '获取评查点组数据失败: 返回数据为空',
status: 404
};
}
} catch (error) {
console.error('获取评查点组数据失败:', error);
return {
error: error instanceof Error ? error.message : '获取评查点组数据失败',
status: 500
};
}
}
// 用于评查点输入的接口
interface EvaluationPointInput {
@@ -1323,211 +905,6 @@ interface EvaluationPointInput {
score?: number;
}
/**
* 保存评查点数据
* @param evaluationPoint 评查点数据
* @param isEditMode 是否为编辑模式
* @returns 保存结果
*/
export async function saveEvaluationPoint(evaluationPoint: EvaluationPointInput, isEditMode: boolean): Promise<{
data?: FormattedEvaluationPoint[];
error?: string;
status?: number;
}> {
try {
// console.log(`${isEditMode ? '更新' : '创建'}评查点数据`);
// 创建一个符合数据库模式的数据副本
const cleanedData = {
id: evaluationPoint.id,
name: evaluationPoint.name?.trim(),
code: evaluationPoint.code?.trim(),
risk: evaluationPoint.risk || 'low',
is_enabled: evaluationPoint.is_enabled !== undefined ? evaluationPoint.is_enabled : true,
description: evaluationPoint.description || '',
references_laws: evaluationPoint.references_laws || null,
evaluation_point_groups_pid: evaluationPoint.evaluation_point_groups_pid || null,
evaluation_point_groups_id: evaluationPoint.evaluation_point_groups_id || null,
extraction_config: {
llm: {
fields: Array.isArray(evaluationPoint.extraction_config?.llm?.fields) ?
[...evaluationPoint.extraction_config.llm.fields] : [],
prompt_setting: {
type: evaluationPoint.extraction_config?.llm?.prompt_setting?.type || 'system',
template: evaluationPoint.extraction_config?.llm?.prompt_setting?.template || ''
}
},
vlm: {
fields: Array.isArray(evaluationPoint.extraction_config?.vlm?.fields) ?
[...evaluationPoint.extraction_config.vlm.fields] : [],
prompt_setting: {
type: evaluationPoint.extraction_config?.vlm?.prompt_setting?.type || 'system',
template: evaluationPoint.extraction_config?.vlm?.prompt_setting?.template || ''
}
},
regex: {
fields: Array.isArray(evaluationPoint.extraction_config?.regex?.fields) ?
[...evaluationPoint.extraction_config.regex.fields] : []
}
},
evaluation_config: {
logicType: evaluationPoint.evaluation_config?.logicType || 'and',
customLogic: evaluationPoint.evaluation_config?.customLogic || '',
rules: Array.isArray(evaluationPoint.evaluation_config?.rules) ?
evaluationPoint.evaluation_config.rules.map((rule) => ({
id: rule.id || '1',
type: rule.type || '',
config: rule.config || {}
})) : []
},
pass_message: evaluationPoint.pass_message || '文档检查通过,符合规范要求。',
fail_message: evaluationPoint.fail_message || '文档存在以下问题,请修改后重新提交。',
suggestion_message: evaluationPoint.suggestion_message || '',
suggestion_message_type: evaluationPoint.suggestion_message_type || 'warning',
post_action: evaluationPoint.post_action || 'none',
action_config: evaluationPoint.action_config || '',
score: evaluationPoint.score !== undefined ? Number(evaluationPoint.score) : 0
};
// 如果是新建模式,则删除id字段
if (!isEditMode) {
delete cleanedData.id;
}
// 确保配置对象中的规则配置被正确处理
if (cleanedData.evaluation_config && Array.isArray(cleanedData.evaluation_config.rules)) {
cleanedData.evaluation_config.rules = cleanedData.evaluation_config.rules
.filter(rule => rule && rule.type) // 确保规则有类型
.map(rule => {
// 根据规则类型确保config中有必要的字段
const config = { ...rule.config };
// 移除辅助字段(同rules.new.tsx中的逻辑)
switch (rule.type) {
case 'exists':
if (!Array.isArray(config.fields)) config.fields = [];
if (!config.logic) config.logic = 'and';
delete config.availableFields;
delete config.selectedFields;
delete config.existsLogic;
break;
case 'consistency':
if (!Array.isArray(config.pairs)) config.pairs = [];
if (!config.logic) config.logic = 'and';
delete config.availableFields;
delete config.logicRelation;
delete config.initialSourceField;
delete config.initialTargetField;
delete config.initialCompareMethod;
break;
case 'format':
if (!config.field) config.field = '';
if (!config.formatType) config.formatType = 'date';
if (!config.parameters) config.parameters = '';
delete config.availableFields;
delete config.checkField;
delete config.formatParams;
break;
case 'logic':
if (!Array.isArray(config.conditions)) config.conditions = [];
if (!config.logic) config.logic = 'and';
delete config.availableFields;
delete config.logicRelation;
delete config.initialField;
delete config.initialOperator;
delete config.initialValue;
break;
case 'regex':
if (!config.field) config.field = '';
if (!config.pattern) config.pattern = '';
if (!config.matchType) config.matchType = 'match';
delete config.availableFields;
delete config.checkField;
delete config.regexPattern;
break;
case 'ai':
if (!config.model) config.model = 'qwen14b';
if (typeof config.temperature !== 'number') config.temperature = 0.1;
if (!config.prompt) config.prompt = '';
delete config.availableFields;
break;
case 'code':
if (!config.language) config.language = 'javascript';
if (!config.code) config.code = '';
delete config.availableFields;
break;
}
return {
id: rule.id,
type: rule.type,
config
};
});
}
// console.log("准备发送到API的数据大小:", JSON.stringify(cleanedData).length, "字节");
// 使用 postgrest-client 替代直接 fetch 调用
let response;
if (isEditMode) {
// 更新操作
response = await postgrestPut<{code: number; msg: string; data: ApiRule} | ApiRule, typeof cleanedData>(
`/api/postgrest/proxy/evaluation_points`,
cleanedData,
{id: cleanedData.id!}
);
} else {
// 创建操作
response = await postgrestPost<{code: number; msg: string; data: ApiRule} | ApiRule, typeof cleanedData>(
'/api/postgrest/proxy/evaluation_points',
cleanedData
);
}
// 处理错误响应
if (response.error) {
return {
error: response.error,
status: response.status
};
}
// 使用 extractApiData 统一处理响应数据
const extractedData = extractApiData<ApiRule | ApiRule[]>(response.data);
if (extractedData) {
// 转换数据格式后返回
if (Array.isArray(extractedData)) {
return {
data: extractedData.map(rule => convertApiRuleToFormData(rule))
};
} else {
return {
data: [convertApiRuleToFormData(extractedData)]
};
}
} else {
return {
error: `${isEditMode ? '更新' : '创建'}评查点数据失败: 返回数据为空`,
status: 404
};
}
} catch (error) {
console.error("保存评查点失败:", error);
return {
error: error instanceof Error ? error.message : '保存评查点失败',
status: 500
};
}
}
/**
* 评查点统计信息
@@ -1548,129 +925,6 @@ export interface RuleStatistics {
}>;
}
/**
* 获取评查点统计信息
* @param token JWT token (可选)
* @returns 评查点统计数据
*/
export async function getRuleStatistics(token?: string): Promise<{data: RuleStatistics; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 1. 获取所有评查点基本数据(不需要分页)
const postgrestParams: PostgrestParams = {
select: 'id,is_enabled,risk,evaluation_point_groups_id',
token
};
const response = await postgrestGet<{code: number; msg: string; data: Array<{
id: number;
is_enabled: boolean;
risk: string;
evaluation_point_groups_id: number | null;
}>}>('/api/postgrest/proxy/evaluation_points', postgrestParams);
// 检查是否有错误响应
if (response.error) {
return { error: response.error, status: response.status };
}
// 提取数据
let evaluationPoints: Array<{
id: number;
is_enabled: boolean;
risk: string;
evaluation_point_groups_id: number | null;
}> = [];
if (response.data && 'code' in response.data && response.data.data) {
if (Array.isArray(response.data.data)) {
evaluationPoints = response.data.data;
}
} else if (Array.isArray(response.data)) {
evaluationPoints = response.data;
}
// 2. 计算基础统计
const totalCount = evaluationPoints.length;
const enabledCount = evaluationPoints.filter(p => p.is_enabled).length;
const disabledCount = totalCount - enabledCount;
// 3. 按风险等级统计
const byRisk = {
low: evaluationPoints.filter(p => p.risk === '低').length,
medium: evaluationPoints.filter(p => p.risk === '中').length,
high: evaluationPoints.filter(p => p.risk === '高').length
};
// 4. 按规则组统计
const groupCountMap = new Map<number, number>();
evaluationPoints.forEach(point => {
if (point.evaluation_point_groups_id !== null) {
const currentCount = groupCountMap.get(point.evaluation_point_groups_id) || 0;
groupCountMap.set(point.evaluation_point_groups_id, currentCount + 1);
}
});
// 5. 获取规则组名称
const groupIds = Array.from(groupCountMap.keys());
const byGroup: Array<{
group_id: number;
group_name: string;
count: number;
}> = [];
if (groupIds.length > 0) {
// 批量查询规则组信息
const groupsParams: PostgrestParams = {
select: 'id,name',
filter: {
'id': `in.(${groupIds.join(',')})`
},
token
};
const groupsResponse = await postgrestGet<{code: number; msg: string; data: Array<{id: number; name: string}>}>('/api/postgrest/proxy/evaluation_point_groups', groupsParams);
let groups: Array<{id: number; name: string}> = [];
if (groupsResponse.data && 'code' in groupsResponse.data && groupsResponse.data.data) {
if (Array.isArray(groupsResponse.data.data)) {
groups = groupsResponse.data.data;
}
} else if (Array.isArray(groupsResponse.data)) {
groups = groupsResponse.data;
}
// 组合统计数据
groups.forEach(group => {
byGroup.push({
group_id: group.id,
group_name: group.name,
count: groupCountMap.get(group.id) || 0
});
});
// 按数量降序排序
byGroup.sort((a, b) => b.count - a.count);
}
// 返回统计结果
const statistics: RuleStatistics = {
total_count: totalCount,
enabled_count: enabledCount,
disabled_count: disabledCount,
by_risk: byRisk,
by_group: byGroup
};
return { data: statistics };
} catch (error) {
console.error('获取评查点统计信息失败:', error);
return {
error: error instanceof Error ? error.message : '获取评查点统计信息失败',
status: 500
};
}
}
/**
* 批量更新评查点启用状态
@@ -1696,13 +950,6 @@ export async function batchUpdateRuleStatus(
// 逐个验证并更新
for (const id of ids) {
try {
// 验证评查点是否存在
const existingRule = await getRule(id, token);
if (existingRule.error || !existingRule.data) {
failedIds.push(id);
errors.push({ id, error: '评查点不存在' });
continue;
}
// 执行更新
const updateResult = await updateRule(id, { isActive: is_enabled }, token);