f5a5887651
## 主要变更 ### 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 接口定义
2115 lines
65 KiB
TypeScript
2115 lines
65 KiB
TypeScript
import { postgrestGet, postgrestPost, postgrestPut, postgrestDelete, type PostgrestParams } from '../postgrest-client';
|
|
import { formatDate } from '../../utils';
|
|
|
|
/**
|
|
* 从不同格式的 API 响应中提取数据
|
|
* @param responseData API 响应数据
|
|
* @returns 提取后的数据或 null
|
|
*/
|
|
function extractApiData<T>(responseData: unknown): T | null {
|
|
if (!responseData) return null;
|
|
|
|
// 格式1: { code: number, msg: string, data: T }
|
|
if (typeof responseData === 'object' && responseData !== null &&
|
|
'code' in responseData &&
|
|
'data' in responseData &&
|
|
(responseData as { data: unknown }).data) {
|
|
return (responseData as { data: T }).data;
|
|
}
|
|
|
|
// 格式2: 直接是数据对象
|
|
return responseData as T;
|
|
}
|
|
|
|
|
|
/**
|
|
* 评查点列表查询参数
|
|
*/
|
|
export interface RulesQueryParams {
|
|
page?: number;
|
|
pageSize?: number;
|
|
ruleType?: string; // 评查点类型ID (一级分组ID)
|
|
groupId?: string; // 规则组ID (二级分组ID)
|
|
risk?: '高' | '中' | '低'; // 风险等级
|
|
isActive?: boolean;
|
|
keyword?: string;
|
|
area?: string; // 地区过滤
|
|
orderBy?: string;
|
|
orderDirection?: 'asc' | 'desc';
|
|
userRole?: string; // 用户角色
|
|
token?: string; // JWT token
|
|
}
|
|
|
|
/**
|
|
* 评查点列表响应数据
|
|
*/
|
|
export interface RulesListResponse {
|
|
rules: Rule[];
|
|
totalCount: number;
|
|
}
|
|
|
|
/**
|
|
* API返回的评查点详情
|
|
*/
|
|
export interface ApiRule {
|
|
id: number;
|
|
code: string;
|
|
name: string;
|
|
area?: string; // 地区
|
|
evaluation_point_groups_id: number | null;
|
|
risk: string;
|
|
description: string;
|
|
is_enabled: boolean;
|
|
evaluation_point_groups?: {
|
|
first_name: string;
|
|
second_name: string;
|
|
};
|
|
// 🆕 PostgREST 双连接查询返回的字段
|
|
child_group?: {
|
|
id: number;
|
|
name: string;
|
|
} | null;
|
|
parent_group?: {
|
|
id: number;
|
|
name: string;
|
|
} | null;
|
|
references_laws: Record<string, unknown>;
|
|
extraction_config: {
|
|
type: string;
|
|
fields: string[];
|
|
prompt_setting?: {
|
|
type: string;
|
|
template: string;
|
|
};
|
|
};
|
|
evaluation_config: {
|
|
rules: Array<{
|
|
id: string;
|
|
type: string;
|
|
config: Record<string, unknown>;
|
|
}>;
|
|
logicType: string;
|
|
};
|
|
pass_message: string;
|
|
fail_message: string;
|
|
suggestion_message: string;
|
|
suggestion_message_type: string;
|
|
post_action: string;
|
|
action_config: string;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
/**
|
|
* 评查点详情(前端模型)
|
|
*/
|
|
export interface Rule {
|
|
id: string;
|
|
code: string;
|
|
name: string;
|
|
ruleType: string;
|
|
groupId: string;
|
|
groupName: string;
|
|
priority: string;
|
|
description: string;
|
|
isActive: boolean;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
/**
|
|
* 映射API返回的评查点数据到前端模型
|
|
* @param apiRule API返回的评查点数据
|
|
* @returns 前端评查点模型
|
|
*/
|
|
function mapApiRuleToFrontendModel(apiRule: ApiRule): Rule {
|
|
// 风险等级映射到优先级
|
|
const priorityMap: Record<string, string> = {
|
|
'高': 'high',
|
|
'中': 'medium',
|
|
'低': 'low'
|
|
};
|
|
|
|
// 🆕 优先使用 PostgREST 双连接查询返回的数据
|
|
let ruleType = '';
|
|
let groupName = '';
|
|
let groupId = '';
|
|
|
|
if (apiRule.child_group || apiRule.parent_group) {
|
|
// 有 PostgREST 双连接查询数据(外键约束方式)
|
|
groupId = apiRule.child_group?.id.toString() || '';
|
|
groupName = apiRule.child_group?.name || '';
|
|
ruleType = apiRule.parent_group?.name || '';
|
|
} else if (apiRule.evaluation_point_groups) {
|
|
// 兼容旧的查询方式(RPC 函数或手动拼接)
|
|
const isGroupIdEmpty = !apiRule.evaluation_point_groups_id;
|
|
ruleType = isGroupIdEmpty ? '' : (apiRule.evaluation_point_groups.first_name || '');
|
|
groupName = isGroupIdEmpty ? '' : (apiRule.evaluation_point_groups.second_name || `${apiRule.evaluation_point_groups_id}`);
|
|
groupId = isGroupIdEmpty ? '' : apiRule.evaluation_point_groups_id?.toString() || '';
|
|
} else {
|
|
// 没有任何分组信息
|
|
const isGroupIdEmpty = !apiRule.evaluation_point_groups_id;
|
|
groupId = isGroupIdEmpty ? '' : apiRule.evaluation_point_groups_id?.toString() || '';
|
|
}
|
|
|
|
// 🔑 清洗评查点编码:移除最后一个 '--' 及其后面的字符
|
|
// 例如:'code-mis--mz' --> 'code-mis', 'code-mbs--alsi--gz' --> 'code-mbs--alsi'
|
|
let cleanedCode = apiRule.code || '';
|
|
const lastDoubleHyphenIndex = cleanedCode.lastIndexOf('--');
|
|
if (lastDoubleHyphenIndex !== -1) {
|
|
cleanedCode = cleanedCode.substring(0, lastDoubleHyphenIndex);
|
|
}
|
|
|
|
return {
|
|
id: apiRule.id ? apiRule.id.toString() : '',
|
|
code: cleanedCode,
|
|
name: apiRule.name || '',
|
|
ruleType: ruleType,
|
|
groupId: groupId,
|
|
groupName: groupName,
|
|
priority: priorityMap[apiRule.risk] || 'medium',
|
|
description: apiRule.description || '',
|
|
isActive: apiRule.is_enabled === undefined ? false : apiRule.is_enabled,
|
|
createdAt: apiRule.created_at,
|
|
updatedAt: apiRule.updated_at
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 获取评查点列表
|
|
* @param params 查询参数
|
|
* @returns 评查点列表、总数和评查点组
|
|
*/
|
|
export async function getRulesList(params: RulesQueryParams): Promise<{data: RulesListResponse; error?: never} | {data?: never; error: string; status?: number}> {
|
|
try {
|
|
// 解构并设置默认值
|
|
const {
|
|
page = 1,
|
|
pageSize = 10,
|
|
ruleType,
|
|
groupId,
|
|
risk,
|
|
isActive,
|
|
keyword,
|
|
area,
|
|
orderBy = 'created_at',
|
|
orderDirection = 'desc',
|
|
userRole,
|
|
token
|
|
} = params;
|
|
|
|
// 🔑 如果没有传递 userRole,尝试从 localStorage 中获取
|
|
let user_role = ''
|
|
if (!userRole && typeof window !== 'undefined' && window.localStorage) {
|
|
try {
|
|
const userInfoStr = localStorage.getItem('user_info');
|
|
if (userInfoStr) {
|
|
const userInfo = JSON.parse(userInfoStr);
|
|
user_role = userInfo.user_role || userInfo.userRole;
|
|
// console.log('📋 [getRulesList] 从 localStorage 获取用户角色:', userRole);
|
|
}
|
|
} catch (error) {
|
|
console.error('❌ [getRulesList] 解析 localStorage 用户信息失败:', error);
|
|
}
|
|
}
|
|
|
|
// 构建PostgrestParams参数
|
|
const postgrestParams: PostgrestParams = {
|
|
// 🆕 使用 PostgREST 双连接查询(直接连接父子分组)
|
|
// child_group: 通过 evaluation_point_groups_id 获取子分组(所属规则组)
|
|
// parent_group: 通过 evaluation_point_groups_pid 直接获取父分组(评查点类型)
|
|
// ⚠️ 重要:使用 .replace() 移除换行符,PostgREST 的 select 参数不支持多行字符串
|
|
select: `
|
|
id,
|
|
code,
|
|
name,
|
|
area,
|
|
evaluation_point_groups_id,
|
|
evaluation_point_groups_pid,
|
|
risk,
|
|
description,
|
|
is_enabled,
|
|
created_at,
|
|
updated_at,
|
|
child_group:evaluation_point_groups!fk_evaluation_points_group(id,name),
|
|
parent_group:evaluation_point_groups!fk_evaluation_points_parent_group(id,name)
|
|
`.replace(/\s+/g, ' ').trim(),
|
|
// 设置分页
|
|
limit: pageSize,
|
|
offset: (page - 1) * pageSize,
|
|
|
|
// 设置排序
|
|
order: `${orderBy}.${orderDirection}`,
|
|
|
|
// 构建过滤条件
|
|
filter: {},
|
|
|
|
// 添加额外头部,用于获取总记录数
|
|
headers: {
|
|
'Prefer': 'count=exact'
|
|
},
|
|
token
|
|
};
|
|
|
|
// 添加精确匹配过滤:规则组ID
|
|
if (groupId) {
|
|
postgrestParams.filter!['evaluation_point_groups_id'] = `eq.${groupId}`;
|
|
}
|
|
|
|
// 添加风险等级筛选
|
|
if (risk) {
|
|
postgrestParams.filter!['risk'] = `eq.${risk}`;
|
|
}
|
|
|
|
if (isActive !== undefined) {
|
|
postgrestParams.filter!['is_enabled'] = `eq.${isActive}`;
|
|
}
|
|
|
|
// 🔑 添加地区过滤
|
|
if (user_role == 'provincial_admin') {
|
|
postgrestParams.filter!['area'] = `eq.省级`;
|
|
}else{
|
|
postgrestParams.filter!['area'] = `eq.${area}`;
|
|
}
|
|
|
|
// 如果指定了评查点类型ID,需要先查询该类型下的所有规则组ID
|
|
if (ruleType) {
|
|
try {
|
|
// 🔑 检查是否为多个类型(逗号分隔)
|
|
const isMultipleTypes = ruleType.includes(',');
|
|
|
|
// 先获取该类型(或多个类型)下的所有规则组
|
|
const groupsParams: PostgrestParams = {
|
|
select: 'id',
|
|
filter: {
|
|
// 如果是多个类型,使用 in.(type1,type2),否则使用 eq.type
|
|
'pid': isMultipleTypes ? `in.(${ruleType})` : `eq.${ruleType}`
|
|
},
|
|
token
|
|
};
|
|
|
|
const groupsResponse = await postgrestGet<{code: number; msg: string; data: Array<{id: number}>}>('evaluation_point_groups', groupsParams);
|
|
|
|
if (groupsResponse.error) {
|
|
console.error('获取规则组列表失败:', groupsResponse.error);
|
|
} else {
|
|
let groupIds: number[] = [];
|
|
|
|
// 处理不同API响应格式
|
|
if (groupsResponse.data && 'code' in groupsResponse.data && groupsResponse.data.data) {
|
|
if (Array.isArray(groupsResponse.data.data) && groupsResponse.data.data.length > 0) {
|
|
groupIds = groupsResponse.data.data.map(group => group.id);
|
|
}
|
|
} else if (Array.isArray(groupsResponse.data) && groupsResponse.data.length > 0) {
|
|
groupIds = groupsResponse.data.map(group => group.id);
|
|
}
|
|
|
|
// 使用in过滤条件,如果找到规则组
|
|
if (groupIds.length > 0) {
|
|
postgrestParams.filter!['evaluation_point_groups_id'] = `in.(${groupIds.join(',')})`;
|
|
}
|
|
if (groupId) {
|
|
postgrestParams.filter!['evaluation_point_groups_id'] = `eq.${groupId}`;
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('获取规则组ID出错:', error);
|
|
// 错误不中断流程,继续使用其他筛选条件
|
|
}
|
|
}
|
|
|
|
// 添加模糊搜索
|
|
if (keyword) {
|
|
// 使用PostgREST的or条件查询
|
|
// 同时搜索name和code字段
|
|
postgrestParams.or = [
|
|
{ name: `ilike.*${keyword}*` },
|
|
{ code: `ilike.*${keyword}*` }
|
|
];
|
|
}
|
|
|
|
// 使用postgrestGet发送请求
|
|
const response = await postgrestGet<{code: number; msg: string; data: ApiRule[]}>('evaluation_points', postgrestParams);
|
|
|
|
// 检查是否有错误响应
|
|
if (response.error) {
|
|
return { error: response.error, status: response.status };
|
|
}
|
|
|
|
// 处理不同的API响应格式
|
|
let apiRules: ApiRule[] = [];
|
|
let totalCount = 0;
|
|
|
|
// 9000端口格式 {code: number, msg: string, data: ApiRule[]}
|
|
if (response.data && 'code' in response.data && response.data.data) {
|
|
if (Array.isArray(response.data.data)) {
|
|
apiRules = response.data.data;
|
|
} else {
|
|
return { error: '接口返回数据格式不正确', status: 500 };
|
|
}
|
|
}
|
|
// 3000端口格式 ApiRule[]
|
|
else if (Array.isArray(response.data)) {
|
|
apiRules = response.data;
|
|
}
|
|
// 不支持的格式
|
|
else {
|
|
return { error: '接口返回数据格式不正确', status: 500 };
|
|
}
|
|
|
|
// 尝试从响应中获取总数
|
|
let rangeHeader = '';
|
|
|
|
// 安全地检查头信息是否存在
|
|
if (response && 'headers' in response && response.headers && typeof response.headers === 'object') {
|
|
rangeHeader = (response.headers as Record<string, string>)['content-range'] || '';
|
|
}
|
|
|
|
if (rangeHeader) {
|
|
// 例如 Content-Range: 0-9/42 表示总共有 42 条记录
|
|
const total = rangeHeader.split('/')[1];
|
|
if (total !== '*') { // '*' 表示未知总数
|
|
totalCount = parseInt(total, 10);
|
|
}
|
|
} else {
|
|
// 如果没有响应头,则使用当前返回的数据长度作为默认值
|
|
totalCount = apiRules.length;
|
|
}
|
|
|
|
// 🆕 使用嵌套查询后,不再需要手动查询分组信息
|
|
// PostgREST 的嵌套 select 已经自动关联了分组数据
|
|
console.log('📋 [getRulesList] 使用 PostgREST 嵌套查询获取评查点数据');
|
|
|
|
// 将API返回的数据映射到前端模型
|
|
const mappedRules = apiRules.map(apiRule => {
|
|
const rule = mapApiRuleToFrontendModel(apiRule);
|
|
|
|
// 格式化日期字段
|
|
rule.createdAt = formatDate(rule.createdAt);
|
|
rule.updatedAt = formatDate(rule.updatedAt);
|
|
|
|
return rule;
|
|
});
|
|
|
|
// 返回结果
|
|
return {
|
|
data: {
|
|
rules: mappedRules,
|
|
totalCount
|
|
}
|
|
};
|
|
} 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 getRule(id: string, token?: string): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
|
|
try {
|
|
// 使用postgrestGet获取单个评查点数据
|
|
const postgrestParams: PostgrestParams = {
|
|
// 使用PostgREST资源嵌入语法获取关联数据
|
|
select: `
|
|
id,
|
|
code,
|
|
name,
|
|
evaluation_point_groups_id,
|
|
risk,
|
|
description,
|
|
is_enabled,
|
|
references_laws,
|
|
extraction_config,
|
|
evaluation_config,
|
|
pass_message,
|
|
fail_message,
|
|
suggestion_message,
|
|
suggestion_message_type,
|
|
post_action,
|
|
action_config,
|
|
created_at,
|
|
updated_at
|
|
`,
|
|
token
|
|
};
|
|
|
|
// 获取评查点详情
|
|
const response = await postgrestGet<{code: number; msg: string; data: ApiRule}>(`evaluation_points/${id}`, postgrestParams);
|
|
|
|
// 检查是否有错误响应
|
|
if (response.error) {
|
|
return { error: response.error, status: response.status };
|
|
}
|
|
|
|
// 确保响应数据存在且符合预期格式
|
|
if (!response.data || !response.data.data) {
|
|
return { error: '接口返回数据格式不正确', status: 500 };
|
|
}
|
|
|
|
const apiRule = response.data.data;
|
|
|
|
// 获取分组信息
|
|
try {
|
|
if (apiRule.evaluation_point_groups_id) {
|
|
const groupParams: PostgrestParams = {
|
|
select: 'id,name',
|
|
filter: {
|
|
'id': `eq.${apiRule.evaluation_point_groups_id}`
|
|
},
|
|
token
|
|
};
|
|
|
|
// 查询评查点分组
|
|
const groupResponse = await postgrestGet<{code: number; msg: string; data: {id: number; name: string}[]}>('evaluation_point_groups', groupParams);
|
|
|
|
if (groupResponse.data?.data && groupResponse.data.data.length > 0) {
|
|
// 将分组信息添加到评查点数据中
|
|
const group = groupResponse.data.data[0];
|
|
apiRule.evaluation_point_groups = {
|
|
first_name: group.name,
|
|
second_name: group.name
|
|
};
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('获取分组信息失败:', error);
|
|
// 忽略错误,使用默认分组名
|
|
}
|
|
|
|
// 将API返回的数据映射到前端模型
|
|
const rule = mapApiRuleToFrontendModel(apiRule);
|
|
|
|
// 格式化日期字段
|
|
rule.createdAt = formatDate(rule.createdAt);
|
|
rule.updatedAt = formatDate(rule.updatedAt);
|
|
|
|
return { data: rule };
|
|
} catch (error) {
|
|
console.error('获取评查点详情出错:', error);
|
|
return {
|
|
error: error instanceof Error ? error.message : '获取评查点详情失败',
|
|
status: 500
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 创建新评查点
|
|
* @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}> }>('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>('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}> }>('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更新评查点
|
|
const response = await postgrestPut<{code: number; msg: string; data: ApiRule}, typeof apiRuleData>(`evaluation_points/${id}`, apiRuleData, undefined, 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 token JWT token (可选)
|
|
* @returns 删除结果
|
|
*/
|
|
export async function deleteRule(id: string, token?: string): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
|
|
try {
|
|
// 1. 验证评查点是否存在
|
|
const existingRuleResponse = await getRule(id, token);
|
|
if (existingRuleResponse.error || !existingRuleResponse.data) {
|
|
return { error: '评查点不存在', status: 404 };
|
|
}
|
|
|
|
// 2. 检查是否有关联的评查结果
|
|
// 注意:这里假设存在 evaluation_results 表,如果不存在可以跳过此检查
|
|
try {
|
|
const resultsParams: PostgrestParams = {
|
|
select: 'id',
|
|
filter: {
|
|
'evaluation_point_id': `eq.${id}`
|
|
},
|
|
limit: 1, // 只需要知道是否存在,不需要全部
|
|
token
|
|
};
|
|
|
|
const resultsResponse = await postgrestGet<{code: number; msg: string; data: Array<{id: number}>}>('evaluation_results', resultsParams);
|
|
|
|
let hasResults = false;
|
|
if (resultsResponse.data && 'code' in resultsResponse.data && resultsResponse.data.data) {
|
|
hasResults = Array.isArray(resultsResponse.data.data) && resultsResponse.data.data.length > 0;
|
|
} else if (Array.isArray(resultsResponse.data)) {
|
|
hasResults = resultsResponse.data.length > 0;
|
|
}
|
|
|
|
if (hasResults) {
|
|
return {
|
|
error: '该评查点已被使用,无法删除。如需停用,请使用禁用功能。',
|
|
status: 400
|
|
};
|
|
}
|
|
} catch (error) {
|
|
// 如果 evaluation_results 表不存在,忽略此错误并继续删除
|
|
console.warn('检查评查结果关联时出错(表可能不存在):', error);
|
|
}
|
|
|
|
// 3. 使用 PostgREST 语法,通过查询参数指定要删除的行
|
|
const postgrestParams: PostgrestParams = {
|
|
filter: {
|
|
'id': `eq.${id}`
|
|
},
|
|
headers: {
|
|
'Prefer': 'return=representation' // 请求返回被删除的记录
|
|
},
|
|
token
|
|
};
|
|
|
|
// 使用postgrestDelete删除评查点
|
|
const response = await postgrestDelete('evaluation_points', postgrestParams);
|
|
|
|
// console.log('删除请求响应:', JSON.stringify(response, null, 2));
|
|
|
|
// 检查是否有错误响应
|
|
if (response.error) {
|
|
console.error('删除评查点API返回错误:', response.error);
|
|
return { error: response.error, status: response.status };
|
|
}
|
|
|
|
// 确保响应数据存在
|
|
if (!response.data) {
|
|
console.error('API响应缺少数据字段');
|
|
return { error: 'API返回数据为空', status: 500 };
|
|
}
|
|
|
|
// 创建一个模拟的成功删除结果
|
|
const createMockSuccessRule = (): Rule => {
|
|
return {
|
|
id: id,
|
|
code: '',
|
|
name: '',
|
|
ruleType: '',
|
|
groupId: '',
|
|
groupName: '',
|
|
priority: 'medium',
|
|
description: '',
|
|
isActive: false,
|
|
createdAt: new Date().toISOString(),
|
|
updatedAt: new Date().toISOString()
|
|
};
|
|
};
|
|
|
|
// 处理9000端口响应格式
|
|
if (typeof response.data === 'object' && response.data !== null && 'code' in response.data) {
|
|
const apiResponse = response.data as {code: number; msg: string; data?: ApiRule | ApiRule[]};
|
|
|
|
// 检查响应的code - 如果code为0则表示操作成功
|
|
if (apiResponse.code === 0) {
|
|
// 如果data不存在或是空数组,返回模拟数据
|
|
if (!apiResponse.data || (Array.isArray(apiResponse.data) && apiResponse.data.length === 0)) {
|
|
return { data: createMockSuccessRule() };
|
|
}
|
|
|
|
// 处理存在的data
|
|
let apiRule: ApiRule;
|
|
if (Array.isArray(apiResponse.data)) {
|
|
apiRule = apiResponse.data[0];
|
|
} else {
|
|
apiRule = apiResponse.data;
|
|
}
|
|
|
|
// 将API返回的数据映射到前端模型
|
|
const rule = mapApiRuleToFrontendModel(apiRule);
|
|
return { data: rule };
|
|
}
|
|
|
|
// 如果code不为0,则返回错误信息
|
|
return {
|
|
error: apiResponse.msg || '删除失败,服务器返回错误',
|
|
status: 500
|
|
};
|
|
}
|
|
// 处理3000端口响应格式 (直接返回数据)
|
|
else {
|
|
// 处理数组响应
|
|
if (Array.isArray(response.data)) {
|
|
if (response.data.length === 0) {
|
|
// 空数组表示成功但没有返回数据
|
|
return { data: createMockSuccessRule() };
|
|
} else {
|
|
// 返回数组中的第一个元素
|
|
const apiRule = response.data[0] as ApiRule;
|
|
const rule = mapApiRuleToFrontendModel(apiRule);
|
|
return { data: rule };
|
|
}
|
|
}
|
|
// 处理单一对象响应
|
|
else {
|
|
const apiRule = response.data as ApiRule;
|
|
const rule = mapApiRuleToFrontendModel(apiRule);
|
|
return { data: rule };
|
|
}
|
|
}
|
|
} 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 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
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 评查点类型
|
|
*/
|
|
export interface RuleType {
|
|
id: string;
|
|
name: string;
|
|
description?: string;
|
|
isEnabled: boolean;
|
|
}
|
|
|
|
/**
|
|
* 规则组
|
|
*/
|
|
export interface RuleGroup {
|
|
id: string;
|
|
name: string;
|
|
description?: string;
|
|
isEnabled: boolean;
|
|
typeId?: string; // 关联的评查点类型ID
|
|
}
|
|
|
|
/**
|
|
* 获取评查点类型列表
|
|
* @param documentTypeIds 文档类型 ID 列表
|
|
* @param token JWT token (可选)
|
|
* @returns 评查点类型列表
|
|
*/
|
|
export async function getRuleTypes(documentTypeIds?: number[], token?: string): Promise<{data: RuleType[]; error?: never} | {data?: never; error: string; status?: number}> {
|
|
try {
|
|
|
|
const documentTypesParams: PostgrestParams = {
|
|
select: 'id, name, evaluation_point_groups_ids',
|
|
filter: {},
|
|
token
|
|
};
|
|
|
|
const documentTypesResponse = await postgrestGet<{
|
|
code: number;
|
|
msg: string;
|
|
data: Array<{
|
|
id: number;
|
|
name: string;
|
|
evaluation_point_groups_ids: number[];
|
|
}>
|
|
}>('document_types', documentTypesParams);
|
|
|
|
if (documentTypesResponse.error) {
|
|
return { error: documentTypesResponse.error, status: documentTypesResponse.status };
|
|
}
|
|
|
|
// 提取 document_types 数据
|
|
let documentTypesData: Array<{
|
|
id: number;
|
|
name: string;
|
|
evaluation_point_groups_ids: number[];
|
|
}> = [];
|
|
|
|
if (documentTypesResponse.data && 'code' in documentTypesResponse.data && documentTypesResponse.data.data) {
|
|
if (Array.isArray(documentTypesResponse.data.data)) {
|
|
documentTypesData = documentTypesResponse.data.data;
|
|
}
|
|
} else if (Array.isArray(documentTypesResponse.data)) {
|
|
documentTypesData = documentTypesResponse.data as Array<{
|
|
id: number;
|
|
name: string;
|
|
evaluation_point_groups_ids: number[];
|
|
}>;
|
|
}
|
|
|
|
if (documentTypesData.length === 0) {
|
|
console.warn('getRuleTypes: 未找到对应的文档类型数据');
|
|
return { data: [] };
|
|
}
|
|
|
|
// 2️⃣ 提取并组合所有的 evaluation_point_groups_ids
|
|
const allGroupIds = new Set<number>();
|
|
documentTypesData.forEach(docType => {
|
|
if (Array.isArray(docType.evaluation_point_groups_ids)) {
|
|
docType.evaluation_point_groups_ids.forEach(id => allGroupIds.add(id));
|
|
}
|
|
});
|
|
|
|
if (allGroupIds.size === 0) {
|
|
console.warn('getRuleTypes: 未找到评查点组 ID');
|
|
return { data: [] };
|
|
}
|
|
|
|
// console.log('📋 [getRuleTypes] 提取的评查点组 IDs:', Array.from(allGroupIds));
|
|
|
|
// 3️⃣ 根据组合后的 ID 查询 evaluation_point_groups 表
|
|
const groupIdsStr = Array.from(allGroupIds).join(',');
|
|
const groupsParams: PostgrestParams = {
|
|
select: `
|
|
id,
|
|
pid,
|
|
code,
|
|
name,
|
|
description,
|
|
is_enabled
|
|
`,
|
|
filter: {
|
|
'id': `in.(${groupIdsStr})`,
|
|
'pid': 'eq.0'
|
|
},
|
|
token
|
|
};
|
|
|
|
const response = await postgrestGet<{
|
|
code: number;
|
|
msg: string;
|
|
data: Array<{
|
|
id: number;
|
|
pid: number;
|
|
code: string;
|
|
name: string;
|
|
description: string;
|
|
is_enabled: boolean;
|
|
}>
|
|
}>('evaluation_point_groups', groupsParams);
|
|
|
|
// 检查是否有错误响应
|
|
if (response.error) {
|
|
return { error: response.error, status: response.status };
|
|
}
|
|
|
|
// 处理响应数据
|
|
if (response.data && 'code' in response.data && response.data.data) {
|
|
if (Array.isArray(response.data.data)) {
|
|
const ruleTypes = response.data.data.map(item => ({
|
|
id: item.id.toString(),
|
|
pid: item.pid.toString(),
|
|
code: item.code,
|
|
name: item.name,
|
|
description: item.description,
|
|
isEnabled: item.is_enabled
|
|
}));
|
|
// console.log('📋 [getRuleTypes] 返回评查点类型:', ruleTypes);
|
|
return { data: ruleTypes };
|
|
} else {
|
|
return { data: [] };
|
|
}
|
|
} else if (Array.isArray(response.data)) {
|
|
const ruleTypes = response.data.map(item => ({
|
|
id: item.id.toString(),
|
|
pid: item.pid.toString(),
|
|
code: item.code,
|
|
name: item.name,
|
|
description: item.description,
|
|
isEnabled: item.is_enabled
|
|
}));
|
|
// console.log('📋 [getRuleTypes] 返回评查点类型:', ruleTypes);
|
|
return { data: ruleTypes };
|
|
} else {
|
|
return { data: [] };
|
|
}
|
|
} catch (error) {
|
|
console.error('获取评查点类型出错:', error);
|
|
return {
|
|
error: error instanceof Error ? error.message : '获取评查点类型失败',
|
|
status: 500
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 根据评查点类型ID获取规则组列表
|
|
* @param typeId 评查点类型ID
|
|
* @param token JWT token (可选)
|
|
* @returns 规则组列表
|
|
*/
|
|
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') {
|
|
return { data: [] };
|
|
}
|
|
|
|
// 构建PostgrestParams参数
|
|
const postgrestParams: PostgrestParams = {
|
|
select: `
|
|
id,
|
|
pid,
|
|
code,
|
|
name,
|
|
description,
|
|
is_enabled
|
|
`,
|
|
// 查询指定类型ID的规则组
|
|
filter: {
|
|
'pid': `eq.${typeId}`
|
|
},
|
|
token
|
|
};
|
|
|
|
// 发送请求获取规则组列表
|
|
const response = await postgrestGet<{code: number; msg: string; data: Array<{
|
|
id: number;
|
|
pid: number;
|
|
code: string;
|
|
name: string;
|
|
description: string;
|
|
is_enabled: boolean;
|
|
}>;
|
|
}>('evaluation_point_groups', postgrestParams);
|
|
|
|
// 检查是否有错误响应
|
|
if (response.error) {
|
|
return { error: response.error, status: response.status };
|
|
}
|
|
|
|
// 确保响应数据存在且符合预期格式
|
|
if(response.data && 'code' in response.data && response.data.data){
|
|
if(Array.isArray(response.data.data) && response.data.data.length > 0){
|
|
// 将API返回的数据映射到前端模型
|
|
const ruleGroups = response.data.data.map(item => ({
|
|
id: item.id.toString(),
|
|
name: item.name,
|
|
description: item.description,
|
|
isEnabled: item.is_enabled,
|
|
code: item.code
|
|
}));
|
|
return { data: ruleGroups };
|
|
}else{
|
|
return { error: '9000接口返回数据格式不正确', status: 500 };
|
|
}
|
|
}else if(Array.isArray(response.data) && response.data.length > 0){
|
|
// console.log("评查点类型列表",response.data);
|
|
const ruleGroups = response.data.map(item => ({
|
|
id: item.id.toString(),
|
|
name: item.name,
|
|
description: item.description,
|
|
isEnabled: item.is_enabled,
|
|
code: item.code
|
|
}));
|
|
return { data: ruleGroups };
|
|
}else{
|
|
return { error: '3000接口返回数据格式不正确', status: 500 };
|
|
}
|
|
} catch (error) {
|
|
console.error('获取规则组出错:', error);
|
|
return {
|
|
error: error instanceof Error ? error.message : '获取规则组失败',
|
|
status: 500
|
|
};
|
|
}
|
|
}
|
|
|
|
// 定义提取配置类型
|
|
interface ExtractionConfigType {
|
|
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 }>;
|
|
};
|
|
}
|
|
|
|
// 定义转换后的评查点数据类型
|
|
interface FormattedEvaluationPoint {
|
|
id: number; // 修改为只接受 number 类型
|
|
name: string;
|
|
code: string;
|
|
risk: string;
|
|
is_enabled: boolean;
|
|
description: string;
|
|
references_laws: Record<string, unknown> | null;
|
|
evaluation_point_groups_pid: number | null;
|
|
evaluation_point_groups_id: number | null;
|
|
extraction_config: ExtractionConfigType;
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* 将 API 返回的数据格式转换为前端需要的格式
|
|
* @param apiRule API 返回的评查点数据
|
|
* @returns 转换后的前端格式数据
|
|
*/
|
|
export function convertApiRuleToFormData(apiRule: ApiRule): FormattedEvaluationPoint {
|
|
// 提取旧格式的字段数据
|
|
const extractFields = (): ExtractionConfigType => {
|
|
const fields: ExtractionConfigType = {
|
|
llm: { fields: [], prompt_setting: { type: 'system', template: '' } },
|
|
vlm: { fields: [], prompt_setting: { type: 'system', template: '' } },
|
|
regex: { fields: [] }
|
|
};
|
|
|
|
if (!apiRule.extraction_config) return fields;
|
|
|
|
// 处理不同的字段类型
|
|
if (apiRule.extraction_config.type === 'OCR+LLM' || apiRule.extraction_config.type === 'LLM') {
|
|
fields.llm.fields = apiRule.extraction_config.fields || [];
|
|
if (apiRule.extraction_config.prompt_setting) {
|
|
fields.llm.prompt_setting = {
|
|
type: apiRule.extraction_config.prompt_setting.type || 'system',
|
|
template: apiRule.extraction_config.prompt_setting.template || ''
|
|
};
|
|
}
|
|
} else if (apiRule.extraction_config.type === 'VLM') {
|
|
fields.vlm.fields = apiRule.extraction_config.fields || [];
|
|
if (apiRule.extraction_config.prompt_setting) {
|
|
fields.vlm.prompt_setting = {
|
|
type: apiRule.extraction_config.prompt_setting.type || 'system',
|
|
template: apiRule.extraction_config.prompt_setting.template || ''
|
|
};
|
|
}
|
|
} else if (apiRule.extraction_config.type === 'REGEX') {
|
|
// 将字符串字段转换为 regex 格式对象
|
|
fields.regex.fields = apiRule.extraction_config.fields.map(field => ({
|
|
field,
|
|
pattern: ''
|
|
}));
|
|
}
|
|
|
|
return fields;
|
|
};
|
|
|
|
// 转换后的数据
|
|
const formattedData: FormattedEvaluationPoint = {
|
|
id: typeof apiRule.id === 'string' ? parseInt(apiRule.id, 10) : apiRule.id, // 确保 id 是数字
|
|
name: apiRule.name,
|
|
code: apiRule.code,
|
|
risk: apiRule.risk,
|
|
is_enabled: apiRule.is_enabled,
|
|
description: apiRule.description,
|
|
references_laws: apiRule.references_laws,
|
|
evaluation_point_groups_pid: apiRule.evaluation_point_groups?.first_name ? null : null,
|
|
evaluation_point_groups_id: apiRule.evaluation_point_groups_id,
|
|
extraction_config: extractFields(),
|
|
evaluation_config: {
|
|
logicType: apiRule.evaluation_config?.logicType || 'and',
|
|
customLogic: '',
|
|
rules: apiRule.evaluation_config?.rules || []
|
|
},
|
|
pass_message: apiRule.pass_message || '',
|
|
fail_message: apiRule.fail_message || '',
|
|
suggestion_message: apiRule.suggestion_message || '',
|
|
suggestion_message_type: apiRule.suggestion_message_type || 'warning',
|
|
post_action: apiRule.post_action || 'none',
|
|
action_config: apiRule.action_config || '',
|
|
score: 0
|
|
};
|
|
|
|
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[]>('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[]>('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 {
|
|
id?: number | string;
|
|
name?: string;
|
|
code?: string;
|
|
risk?: string;
|
|
is_enabled?: boolean;
|
|
description?: string;
|
|
references_laws?: Record<string, unknown> | null;
|
|
evaluation_point_groups_pid?: number | null;
|
|
evaluation_point_groups_id?: number | null;
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* 保存评查点数据
|
|
* @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>(
|
|
`evaluation_points`,
|
|
cleanedData,
|
|
{id: cleanedData.id!}
|
|
);
|
|
} else {
|
|
// 创建操作
|
|
response = await postgrestPost<{code: number; msg: string; data: ApiRule} | ApiRule, typeof cleanedData>(
|
|
'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
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 评查点统计信息
|
|
*/
|
|
export interface RuleStatistics {
|
|
total_count: number; // 总评查点数
|
|
enabled_count: number; // 已启用数量
|
|
disabled_count: number; // 已禁用数量
|
|
by_risk: { // 按风险等级分组
|
|
low: number; // 低风险数量
|
|
medium: number; // 中风险数量
|
|
high: number; // 高风险数量
|
|
};
|
|
by_group: Array<{ // 按规则组分组
|
|
group_id: number;
|
|
group_name: string;
|
|
count: number;
|
|
}>;
|
|
}
|
|
|
|
/**
|
|
* 获取评查点统计信息
|
|
* @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;
|
|
}>}>('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}>}>('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
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 批量更新评查点启用状态
|
|
* @param ids 评查点ID列表
|
|
* @param is_enabled 启用状态
|
|
* @param token JWT token (可选)
|
|
* @returns 批量更新结果
|
|
*/
|
|
export async function batchUpdateRuleStatus(
|
|
ids: string[],
|
|
is_enabled: boolean,
|
|
token?: string
|
|
): Promise<{
|
|
success: boolean;
|
|
updated_count: number;
|
|
failed_ids: string[];
|
|
errors?: Array<{ id: string; error: string }>;
|
|
}> {
|
|
const failedIds: string[] = [];
|
|
const errors: Array<{ id: string; error: string }> = [];
|
|
let updatedCount = 0;
|
|
|
|
// 逐个验证并更新
|
|
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);
|
|
if (updateResult.error) {
|
|
failedIds.push(id);
|
|
errors.push({ id, error: updateResult.error });
|
|
} else {
|
|
updatedCount++;
|
|
}
|
|
} catch (error) {
|
|
failedIds.push(id);
|
|
errors.push({
|
|
id,
|
|
error: error instanceof Error ? error.message : '更新失败'
|
|
});
|
|
}
|
|
}
|
|
|
|
return {
|
|
success: failedIds.length === 0,
|
|
updated_count: updatedCount,
|
|
failed_ids: failedIds,
|
|
errors: errors.length > 0 ? errors : undefined
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 批量删除评查点
|
|
* @param ids 评查点ID列表
|
|
* @param token JWT token (可选)
|
|
* @returns 批量删除结果
|
|
*/
|
|
export async function batchDeleteRules(
|
|
ids: string[],
|
|
token?: string
|
|
): Promise<{
|
|
success: boolean;
|
|
deleted_count: number;
|
|
failed_ids: string[];
|
|
errors?: Array<{ id: string; error: string }>;
|
|
}> {
|
|
const failedIds: string[] = [];
|
|
const errors: Array<{ id: string; error: string }> = [];
|
|
let deletedCount = 0;
|
|
|
|
// 逐个验证并删除
|
|
for (const id of ids) {
|
|
try {
|
|
// 使用增强的 deleteRule 函数(包含关联检查)
|
|
const deleteResult = await deleteRule(id, token);
|
|
if (deleteResult.error) {
|
|
failedIds.push(id);
|
|
errors.push({ id, error: deleteResult.error });
|
|
} else {
|
|
deletedCount++;
|
|
}
|
|
} catch (error) {
|
|
failedIds.push(id);
|
|
errors.push({
|
|
id,
|
|
error: error instanceof Error ? error.message : '删除失败'
|
|
});
|
|
}
|
|
}
|
|
|
|
return {
|
|
success: failedIds.length === 0,
|
|
deleted_count: deletedCount,
|
|
failed_ids: failedIds,
|
|
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
|
|
};
|
|
}
|
|
} |