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:
2025-11-25 14:55:42 +08:00
parent 37134ff650
commit f5a5887651
2 changed files with 260 additions and 74 deletions
+63 -62
View File
@@ -48,11 +48,17 @@ import { EVALUATION_OPTIONS } from "~/models/evaluation_points";
import type { EvaluationPointGroup } from "~/models/evaluation_point_groups";
// 导入RuleContext上下文
import { RuleContext } from "~/contexts/RuleContext";
import { postgrestGet, postgrestPost, postgrestPut } from "~/api/postgrest-client";
import { toastService } from '~/components/ui/Toast';
import type { UserRole } from '~/root';
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 { postgrestGet } from '~/api/postgrest-client';
export const meta: MetaFunction = () => {
return [
@@ -277,69 +283,62 @@ export default function RuleNew() {
try {
setIsLoading(true);
// console.log(`获取评查点数据,ID: ${id}, 复制模式: ${isCopy}`);
// 使用 postgrestGet 替代直接调用 fetch
const postgrestParams = {
filter: {
'id': `eq.${id}`
},
token: frontendJWT
};
const response = await postgrestGet('evaluation_points', postgrestParams);
// 使用新的 getEvaluationPoint API 获取数据
const response = await getEvaluationPoint(String(id), frontendJWT);
if (response.error) {
// API返回错误
toastService.error(`获取评查点数据失败: ${response.error}`);
resetFormData();
navigate('/rules');
return;
}
if (response.data) {
// 使用extractApiData从响应中提取数据
const evaluationPoints = extractApiData<EvaluationPoint[]>(response.data);
try {
// 使用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 {
// 使用JSON序列化和反序列化来进行深拷贝,避免浏览器差异
const originalData = evaluationPoints[0];
const jsonString = JSON.stringify(originalData);
const data = JSON.parse(jsonString);
// 🔄 复制模式:删除不应该复制的字段
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');
// 🔄 复制模式:删除不应该复制的字段
if (isCopy) {
delete data.id;
delete data.created_at;
delete data.updated_at;
// usage_count 不在 EvaluationPointData 接口中,但可能存在于响应数据中
if ('usage_count' in data) {
delete (data as Record<string, unknown>).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');
// console.log('📋 复制模式:已清除不应复制的字段(id, created_at, updated_at, usage_count');
}
} 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();
navigate('/rules');
}
} else {
throw new Error(`响应状态: ${response.error}`);
}
} catch (error) {
console.error('获取评查点数据失败:', error);
@@ -802,27 +801,29 @@ export default function RuleNew() {
let response;
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)
} 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.includes('evaluation_points_code_key')) {
toastService.error('在基本信息中:评查点编码已存在,请修改后保存。');
} else {
} else {
toastService.error(`系统繁忙: ${response.error}`);
}
setIsLoading(false);
} else if (response.data && Array.isArray(response.data) && response.data.length > 0) {
} else if (response.data) {
// 获取新创建或更新的评查点ID
const savedPointId = response.data[0]?.id;
const savedPointId = response.data.id;
if (savedPointId) {
// 显示成功消息
toastService.success(`评查点${isEditMode ? '更新' : '创建'}成功!`);
// 保存成功后跳转到编辑页面并重新加载数据
navigate(`/rules/new?id=${savedPointId}`, { replace: true });
// 重新获取评查点数据