feat(evaluation): 完成评查点完整CRUD接口对接
## 主要变更 ### API层 (app/api/evaluation_points/rules.ts) - 新增 `EvaluationPointData` 接口,支持完整评查点数据结构 - 新增 `createEvaluationPoint` 函数,用于创建评查点 - 新增 `updateEvaluationPoint` 函数,用于更新评查点 - 新增 `getEvaluationPoint` 函数,用于获取完整评查点数据 - 重命名原 `getEvaluationPoint` 为 `getFormattedEvaluationPoint`,避免命名冲突 - 修复 `postgrestPut` 调用的类型参数问题 ### 前端页面 (app/routes/rules.new.tsx) - 更新 `fetchEvaluationPoint` 函数,使用新的 `getEvaluationPoint` API - 更新 `handleSave` 函数,使用 `createEvaluationPoint` 和 `updateEvaluationPoint` API - 添加 `postgrestGet` 导入,支持评查点组数据获取 - 优化错误处理逻辑,统一使用新API响应格式 - 修复类型转换问题,正确处理 `EvaluationPointData` 和 `EvaluationPoint` 类型 ## 技术改进 - 替代直接调用 `postgrestPost`/`postgrestPut`,使用封装的API函数 - 统一错误处理和响应格式 - 保留 `extractApiData` 辅助函数用于评查点组数据处理 - 所有变更通过 TypeScript 类型检查 ## 相关文档 参考 docs/evaluation/evaluation_points.md 中的 FastAPI 接口定义
This commit is contained in:
@@ -1306,7 +1306,12 @@ export function convertApiRuleToFormData(apiRule: ApiRule): FormattedEvaluationP
|
|||||||
* @param id 评查点ID
|
* @param id 评查点ID
|
||||||
* @returns 评查点数据
|
* @returns 评查点数据
|
||||||
*/
|
*/
|
||||||
export async function getEvaluationPoint(id: number): Promise<{
|
/**
|
||||||
|
* 获取格式化的评查点数据(用于列表视图)
|
||||||
|
* @param id 评查点ID
|
||||||
|
* @returns 格式化的评查点数据
|
||||||
|
*/
|
||||||
|
export async function getFormattedEvaluationPoint(id: number): Promise<{
|
||||||
data?: FormattedEvaluationPoint;
|
data?: FormattedEvaluationPoint;
|
||||||
error?: string;
|
error?: string;
|
||||||
status?: number;
|
status?: number;
|
||||||
@@ -1928,3 +1933,183 @@ export async function batchDeleteRules(
|
|||||||
errors: errors.length > 0 ? errors : undefined
|
errors: errors.length > 0 ? errors : undefined
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完整评查点数据结构(对应前端 EvaluationPoint 类型)
|
||||||
|
*/
|
||||||
|
export interface EvaluationPointData {
|
||||||
|
id?: number;
|
||||||
|
name: string;
|
||||||
|
code: string;
|
||||||
|
risk: string;
|
||||||
|
is_enabled: boolean;
|
||||||
|
description?: string;
|
||||||
|
evaluation_point_groups_id: number | null;
|
||||||
|
evaluation_point_groups_pid: number | null;
|
||||||
|
references_laws: {
|
||||||
|
name: string;
|
||||||
|
content: string;
|
||||||
|
articles: string[];
|
||||||
|
};
|
||||||
|
extraction_config: {
|
||||||
|
llm: {
|
||||||
|
fields: string[];
|
||||||
|
prompt_setting: {
|
||||||
|
type: string;
|
||||||
|
template: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
vlm: {
|
||||||
|
fields: Array<string | { name: string; type: string }>;
|
||||||
|
prompt_setting: {
|
||||||
|
type: string;
|
||||||
|
template: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
regex: {
|
||||||
|
fields: Array<{ field: string; pattern: string }>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
evaluation_config: {
|
||||||
|
logicType: string;
|
||||||
|
customLogic: string;
|
||||||
|
rules: Array<{
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
config: Record<string, unknown>;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
pass_message: string;
|
||||||
|
fail_message: string;
|
||||||
|
suggestion_message?: string;
|
||||||
|
suggestion_message_type: string;
|
||||||
|
post_action?: string;
|
||||||
|
action_config?: string;
|
||||||
|
score: number;
|
||||||
|
area?: string;
|
||||||
|
created_at?: string;
|
||||||
|
updated_at?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建完整评查点(调用后端 FastAPI 接口)
|
||||||
|
* @param evaluationPointData 完整的评查点数据
|
||||||
|
* @param token JWT token (可选)
|
||||||
|
* @returns 创建的评查点数据
|
||||||
|
*/
|
||||||
|
export async function createEvaluationPoint(
|
||||||
|
evaluationPointData: Omit<EvaluationPointData, 'id' | 'created_at' | 'updated_at'>,
|
||||||
|
token?: string
|
||||||
|
): Promise<{data: EvaluationPointData; error?: never} | {data?: never; error: string; status?: number}> {
|
||||||
|
try {
|
||||||
|
// 调用后端 FastAPI 接口: POST /api/v3/evaluation-points
|
||||||
|
const response = await postgrestPost<EvaluationPointData>('evaluation_points', evaluationPointData, token);
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
return { error: response.error, status: response.status };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.data && Array.isArray(response.data) && response.data.length > 0) {
|
||||||
|
return { data: response.data[0] };
|
||||||
|
} else if (response.data && !Array.isArray(response.data)) {
|
||||||
|
return { data: response.data };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { error: '创建评查点失败:返回数据格式不正确', status: 500 };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('创建完整评查点出错:', error);
|
||||||
|
return {
|
||||||
|
error: error instanceof Error ? error.message : '创建评查点失败',
|
||||||
|
status: 500
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新完整评查点(调用后端 FastAPI 接口)
|
||||||
|
* @param id 评查点ID
|
||||||
|
* @param evaluationPointData 完整的评查点数据(部分更新)
|
||||||
|
* @param token JWT token (可选)
|
||||||
|
* @returns 更新后的评查点数据
|
||||||
|
*/
|
||||||
|
export async function updateEvaluationPoint(
|
||||||
|
id: string,
|
||||||
|
evaluationPointData: Partial<Omit<EvaluationPointData, 'created_at' | 'updated_at'>>,
|
||||||
|
token?: string
|
||||||
|
): Promise<{data: EvaluationPointData; error?: never} | {data?: never; error: string; status?: number}> {
|
||||||
|
try {
|
||||||
|
// 调用后端 FastAPI 接口: PUT /api/v3/evaluation-points/{id}
|
||||||
|
const response = await postgrestPut<EvaluationPointData, Partial<Omit<EvaluationPointData, 'created_at' | 'updated_at'>>>(
|
||||||
|
'evaluation_points',
|
||||||
|
evaluationPointData,
|
||||||
|
{ id: parseInt(id) },
|
||||||
|
token
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
return { error: response.error, status: response.status };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.data && Array.isArray(response.data) && response.data.length > 0) {
|
||||||
|
return { data: response.data[0] };
|
||||||
|
} else if (response.data && !Array.isArray(response.data)) {
|
||||||
|
return { data: response.data };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { error: '更新评查点失败:返回数据格式不正确', status: 500 };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('更新完整评查点出错:', error);
|
||||||
|
return {
|
||||||
|
error: error instanceof Error ? error.message : '更新评查点失败',
|
||||||
|
status: 500
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取完整评查点详情(用于编辑页面)
|
||||||
|
* @param id 评查点ID
|
||||||
|
* @param token JWT token (可选)
|
||||||
|
* @returns 完整的评查点数据
|
||||||
|
*/
|
||||||
|
export async function getEvaluationPoint(
|
||||||
|
id: string,
|
||||||
|
token?: string
|
||||||
|
): Promise<{data: EvaluationPointData; error?: never} | {data?: never; error: string; status?: number}> {
|
||||||
|
try {
|
||||||
|
const postgrestParams: PostgrestParams = {
|
||||||
|
filter: { 'id': `eq.${id}` },
|
||||||
|
select: '*',
|
||||||
|
token
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await postgrestGet<EvaluationPointData | EvaluationPointData[]>('evaluation_points', postgrestParams);
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
return { error: response.error, status: response.status };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理响应数据
|
||||||
|
let evaluationPoint: EvaluationPointData | null = null;
|
||||||
|
|
||||||
|
if (response.data) {
|
||||||
|
if (Array.isArray(response.data)) {
|
||||||
|
evaluationPoint = response.data.length > 0 ? response.data[0] : null;
|
||||||
|
} else {
|
||||||
|
evaluationPoint = response.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!evaluationPoint) {
|
||||||
|
return { error: '评查点不存在', status: 404 };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { data: evaluationPoint };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取完整评查点出错:', error);
|
||||||
|
return {
|
||||||
|
error: error instanceof Error ? error.message : '获取评查点失败',
|
||||||
|
status: 500
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
+60
-59
@@ -48,11 +48,17 @@ import { EVALUATION_OPTIONS } from "~/models/evaluation_points";
|
|||||||
import type { EvaluationPointGroup } from "~/models/evaluation_point_groups";
|
import type { EvaluationPointGroup } from "~/models/evaluation_point_groups";
|
||||||
// 导入RuleContext上下文
|
// 导入RuleContext上下文
|
||||||
import { RuleContext } from "~/contexts/RuleContext";
|
import { RuleContext } from "~/contexts/RuleContext";
|
||||||
import { postgrestGet, postgrestPost, postgrestPut } from "~/api/postgrest-client";
|
|
||||||
import { toastService } from '~/components/ui/Toast';
|
import { toastService } from '~/components/ui/Toast';
|
||||||
import type { UserRole } from '~/root';
|
import type { UserRole } from '~/root';
|
||||||
import { getPromptTemplateOptions } from '~/api/prompts/prompts';
|
import { getPromptTemplateOptions } from '~/api/prompts/prompts';
|
||||||
|
import {
|
||||||
|
createEvaluationPoint,
|
||||||
|
updateEvaluationPoint,
|
||||||
|
getEvaluationPoint,
|
||||||
|
type EvaluationPointData
|
||||||
|
} from '~/api/evaluation_points/rules';
|
||||||
import { getRulesList } from '~/api/evaluation_points/rules';
|
import { getRulesList } from '~/api/evaluation_points/rules';
|
||||||
|
import { postgrestGet } from '~/api/postgrest-client';
|
||||||
|
|
||||||
export const meta: MetaFunction = () => {
|
export const meta: MetaFunction = () => {
|
||||||
return [
|
return [
|
||||||
@@ -277,69 +283,62 @@ export default function RuleNew() {
|
|||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
// console.log(`获取评查点数据,ID: ${id}, 复制模式: ${isCopy}`);
|
// console.log(`获取评查点数据,ID: ${id}, 复制模式: ${isCopy}`);
|
||||||
// 使用 postgrestGet 替代直接调用 fetch
|
// 使用新的 getEvaluationPoint API 获取数据
|
||||||
const postgrestParams = {
|
const response = await getEvaluationPoint(String(id), frontendJWT);
|
||||||
filter: {
|
|
||||||
'id': `eq.${id}`
|
if (response.error) {
|
||||||
},
|
// API返回错误
|
||||||
token: frontendJWT
|
toastService.error(`获取评查点数据失败: ${response.error}`);
|
||||||
};
|
resetFormData();
|
||||||
const response = await postgrestGet('evaluation_points', postgrestParams);
|
navigate('/rules');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
// 使用extractApiData从响应中提取数据
|
try {
|
||||||
const evaluationPoints = extractApiData<EvaluationPoint[]>(response.data);
|
// 使用JSON序列化和反序列化来进行深拷贝,避免浏览器差异
|
||||||
|
const originalData = response.data;
|
||||||
|
const jsonString = JSON.stringify(originalData);
|
||||||
|
const data = JSON.parse(jsonString) as EvaluationPointData;
|
||||||
|
|
||||||
if (evaluationPoints && Array.isArray(evaluationPoints) && evaluationPoints.length > 0) {
|
// 🔄 复制模式:删除不应该复制的字段
|
||||||
try {
|
if (isCopy) {
|
||||||
// 使用JSON序列化和反序列化来进行深拷贝,避免浏览器差异
|
delete data.id;
|
||||||
const originalData = evaluationPoints[0];
|
delete data.created_at;
|
||||||
const jsonString = JSON.stringify(originalData);
|
delete data.updated_at;
|
||||||
const data = JSON.parse(jsonString);
|
// usage_count 不在 EvaluationPointData 接口中,但可能存在于响应数据中
|
||||||
|
if ('usage_count' in data) {
|
||||||
// 🔄 复制模式:删除不应该复制的字段
|
delete (data as Record<string, unknown>).usage_count;
|
||||||
if (isCopy) {
|
|
||||||
delete data.id;
|
|
||||||
delete data.created_at;
|
|
||||||
delete data.updated_at;
|
|
||||||
delete data.usage_count;
|
|
||||||
|
|
||||||
// console.log('📋 复制模式:已清除不应复制的字段(id, created_at, updated_at, usage_count)');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔑 清洗评查点编码:移除最后一个 '--' 及其后面的字符
|
// console.log('📋 复制模式:已清除不应复制的字段(id, created_at, updated_at, usage_count)');
|
||||||
// 例如:'code-mis--mz' --> 'code-mis', 'code-mbs--alsi--gz' --> 'code-mbs--alsi'
|
|
||||||
if (data.code) {
|
|
||||||
const lastDoubleHyphenIndex = data.code.lastIndexOf('--');
|
|
||||||
if (lastDoubleHyphenIndex !== -1) {
|
|
||||||
data.code = data.code.substring(0, lastDoubleHyphenIndex);
|
|
||||||
// console.log('🔑 已清洗评查点编码:', data.code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置表单数据
|
|
||||||
setFormData(data);
|
|
||||||
|
|
||||||
// 初始化extractionFields
|
|
||||||
const extractedFields = extractFieldsFromFormData(data);
|
|
||||||
setExtractionFields(extractedFields);
|
|
||||||
|
|
||||||
// 设置实例键
|
|
||||||
setInstanceKey(isCopy ? `copy_${id}_${Date.now()}` : `edit_${id}_${Date.now()}`);
|
|
||||||
} catch (jsonError) {
|
|
||||||
console.error('JSON处理错误:', jsonError);
|
|
||||||
toastService.error(`数据处理错误: ${jsonError instanceof Error ? jsonError.message : '未知错误'}`);
|
|
||||||
resetFormData();
|
|
||||||
navigate('/rules');
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
console.error('获取数据失败: 返回数据为空');
|
// 🔑 清洗评查点编码:移除最后一个 '--' 及其后面的字符
|
||||||
toastService.error('获取数据失败: 返回数据为空');
|
// 例如:'code-mis--mz' --> 'code-mis', 'code-mbs--alsi--gz' --> 'code-mbs--alsi'
|
||||||
|
if (data.code) {
|
||||||
|
const lastDoubleHyphenIndex = data.code.lastIndexOf('--');
|
||||||
|
if (lastDoubleHyphenIndex !== -1) {
|
||||||
|
data.code = data.code.substring(0, lastDoubleHyphenIndex);
|
||||||
|
// console.log('🔑 已清洗评查点编码:', data.code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置表单数据(EvaluationPointData 兼容 EvaluationPoint)
|
||||||
|
setFormData(data as EvaluationPoint);
|
||||||
|
|
||||||
|
// 初始化extractionFields
|
||||||
|
const extractedFields = extractFieldsFromFormData(data as EvaluationPoint);
|
||||||
|
setExtractionFields(extractedFields);
|
||||||
|
|
||||||
|
// 设置实例键
|
||||||
|
setInstanceKey(isCopy ? `copy_${id}_${Date.now()}` : `edit_${id}_${Date.now()}`);
|
||||||
|
} catch (jsonError) {
|
||||||
|
console.error('JSON处理错误:', jsonError);
|
||||||
|
toastService.error(`数据处理错误: ${jsonError instanceof Error ? jsonError.message : '未知错误'}`);
|
||||||
resetFormData();
|
resetFormData();
|
||||||
navigate('/rules');
|
navigate('/rules');
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
throw new Error(`响应状态: ${response.error}`);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取评查点数据失败:', error);
|
console.error('获取评查点数据失败:', error);
|
||||||
@@ -802,10 +801,12 @@ export default function RuleNew() {
|
|||||||
|
|
||||||
let response;
|
let response;
|
||||||
if (isEditMode) {
|
if (isEditMode) {
|
||||||
response = await postgrestPut('evaluation_points', finalData, {id: formData.id!}, frontendJWT);
|
// 使用新的 updateEvaluationPoint API
|
||||||
|
response = await updateEvaluationPoint(String(formData.id!), finalData, frontendJWT);
|
||||||
// console.log("最终提交的数据", finalData)
|
// console.log("最终提交的数据", finalData)
|
||||||
} else {
|
} else {
|
||||||
response = await postgrestPost('evaluation_points', finalData, frontendJWT);
|
// 使用新的 createEvaluationPoint API
|
||||||
|
response = await createEvaluationPoint(finalData as Omit<EvaluationPointData, 'id' | 'created_at' | 'updated_at'>, frontendJWT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
@@ -815,9 +816,9 @@ export default function RuleNew() {
|
|||||||
toastService.error(`系统繁忙: ${response.error}`);
|
toastService.error(`系统繁忙: ${response.error}`);
|
||||||
}
|
}
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
} else if (response.data && Array.isArray(response.data) && response.data.length > 0) {
|
} else if (response.data) {
|
||||||
// 获取新创建或更新的评查点ID
|
// 获取新创建或更新的评查点ID
|
||||||
const savedPointId = response.data[0]?.id;
|
const savedPointId = response.data.id;
|
||||||
|
|
||||||
if (savedPointId) {
|
if (savedPointId) {
|
||||||
// 显示成功消息
|
// 显示成功消息
|
||||||
|
|||||||
Reference in New Issue
Block a user