Files
leaudit-platform-frontend/app/api/evaluation_points/rules.ts
T

1503 lines
47 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
groupId?: string; // 规则组ID
isActive?: boolean;
keyword?: string;
orderBy?: string;
orderDirection?: 'asc' | 'desc';
reviewType?: string; // 添加 reviewType 参数,值为 contract 或 record
}
/**
* 评查点列表响应数据
*/
export interface RulesListResponse {
rules: Rule[];
totalCount: number;
}
/**
* API返回的评查点详情
*/
export interface ApiRule {
id: number;
code: string;
name: string;
evaluation_point_groups_id: number | null;
risk: string;
description: string;
is_enabled: boolean;
evaluation_point_groups?: {
first_name: string;
second_name: string;
};
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'
};
//评查点类型映射
// 规则类型映射(这里根据实际业务逻辑设置一个默认值)
// const ruleType = 'essential'; // 实际应用中可能需要从其他字段推断
// console.log("apiRule.evaluation_point_groups",apiRule);
// 如果evaluation_point_groups_id为null或空,则不显示ruleType和groupName
const isGroupIdEmpty = !apiRule.evaluation_point_groups_id;
// 规则类型只在有分组ID时才显示
const ruleType = isGroupIdEmpty ? '' : (apiRule.evaluation_point_groups?.first_name || '');
// 规则组名称只在有分组ID时才显示
const groupName = isGroupIdEmpty ? '' : (apiRule.evaluation_point_groups?.second_name || `${apiRule.evaluation_point_groups_id}`);
return {
id: apiRule.id ? apiRule.id.toString() : '', // 添加空值检查
code: apiRule.code || '',
name: apiRule.name || '',
ruleType: ruleType,
groupId: isGroupIdEmpty ? '' : apiRule.evaluation_point_groups_id?.toString() || '',
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,
isActive,
keyword,
orderBy = 'created_at',
orderDirection = 'desc',
reviewType
} = params;
// 构建PostgrestParams参数
const postgrestParams: PostgrestParams = {
// 修改select语句,不使用嵌入查询语法
select: `
id,
code,
name,
evaluation_point_groups_id,
risk,
description,
is_enabled,
created_at,
updated_at
`,
// 设置分页
limit: pageSize,
offset: (page - 1) * pageSize,
// 设置排序
order: `${orderBy}.${orderDirection}`,
// 构建过滤条件
filter: {},
// 添加额外头部,用于获取总记录数
headers: {
'Prefer': 'count=exact'
}
};
// 添加精确匹配过滤:规则组ID
if (groupId) {
postgrestParams.filter!['evaluation_point_groups_id'] = `eq.${groupId}`;
}
if (isActive !== undefined) {
postgrestParams.filter!['is_enabled'] = `eq.${isActive}`;
}
// 根据reviewType添加过滤条件
if (reviewType) {
try {
// 先获取所有评查点组数据,用于找到对应的pid
const groupsAllResponse = await postgrestGet<{code: number; msg: string; data: Array<{id: number; pid: number}>}>('evaluation_point_groups', {
select: 'id,pid'
});
let groups: Array<{id: number; pid: number}> = [];
if (!groupsAllResponse.error) {
if (groupsAllResponse.data && 'code' in groupsAllResponse.data && groupsAllResponse.data.data) {
groups = groupsAllResponse.data.data;
} else if (Array.isArray(groupsAllResponse.data)) {
groups = groupsAllResponse.data;
}
}
// 根据reviewType过滤pid
let pidList: number[] = [];
if (reviewType === 'contract') {
// 合同类型,找到所有pid=3的评查点组
const contractGroups = groups.filter(g => g.pid === 3).map(g => g.id);
pidList = contractGroups;
} else if (reviewType === 'record') {
// 卷宗类型,找到所有pid=1或pid=2的评查点组
const recordGroups = groups.filter(g => g.pid === 1 || g.pid === 2).map(g => g.id);
pidList = recordGroups;
}
// 如果有过滤的组id,则添加到查询条件中
if (pidList.length > 0) {
postgrestParams.filter!['evaluation_point_groups_id'] = `in.(${pidList.join(',')})`;
}
} catch (error) {
console.error('获取评查点组数据出错:', error);
}
}
// 如果指定了评查点类型ID,需要先查询该类型下的所有规则组ID
if (ruleType) {
try {
// 先获取该类型下的所有规则组
const groupsParams: PostgrestParams = {
select: 'id',
filter: {
'pid': `eq.${ruleType}`
}
};
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;
}
// 打印第一个数据项来查看结构(仅用于调试)
// if (apiRules.length > 0) {
// console.log('评查点数据示例:', JSON.stringify(apiRules[0], null, 2));
// }
// 收集所有规则分组ID(实际上是二级分组) (多进行一步查找表的操作)
const groupIds = [...new Set(apiRules.map(rule => rule.evaluation_point_groups_id))];
// 如果有分组ID,查询分组信息 - 更新类型定义
const groupsMap: Record<string, {first_name: string; second_name: string}> = {};
if (groupIds.length > 0) {
try {
// 过滤null和空值
const validGroupIds = groupIds.filter(id => id != null && id.toString().trim() !== '');
if (validGroupIds.length > 0) {
// 使用Promise.all并行查询所有分组信息 - 使用正确的函数名
const groupPromises = validGroupIds.map(id =>
postgrestGet<{code: number; msg: string; data: {id: number; pid: number; name: string; first_name: string; second_name: string}[]}>(
`rpc/get_evaluation_point_group_with_pid?input_id=${id}`
)
);
const groupResponses = await Promise.all(groupPromises);
// console.log("groupResponsesdddddddddddddddddd",groupResponses);
// 处理响应,填充groupsMap
groupResponses.forEach((response) => {
if (!response.error && response.data) {
// 处理不同API响应格式
if (Array.isArray(response.data.data) && response.data.data.length > 0) {
const groupid = response.data.data[1]?.id || "";
groupsMap[groupid] = {
first_name: response.data.data[0]?.name || "",
second_name: response.data.data[1]?.name || ""
};
}else if(Array.isArray(response.data) && response.data.length > 0){
const groupid = response.data[1]?.id || "";
groupsMap[groupid] = {
first_name: response.data[0]?.name || "",
second_name: response.data[1]?.name || ""
};
}
}
});
}
} catch (error) {
console.error('获取分组数据失败:', error);
// 失败不阻止主流程,使用默认分组名
}
}
// 应用本地过滤 - 只在API不支持的情况下使用
const filteredRules = [...apiRules];
// 不再需要本地过滤,因为已经在API层面添加了评查点类型过滤
// 如果进行了本地过滤,则需要调整总记录数
// if (ruleType) {
// totalCount = filteredRules.length;
// }
// 将API返回的数据映射到前端模型,并附加分组名称
// console.log("groupsMap",groupsMap);
const mappedRules = filteredRules.map(apiRule => {
// 创建修改版的apiRule,添加从分组映射获取的名称
const enhancedApiRule = {
...apiRule,
// 从映射中获取分组名称,如果不存在则使用默认值
evaluation_point_groups: {
first_name: groupsMap[apiRule.evaluation_point_groups_id?.toString() || '']?.first_name || `${apiRule.evaluation_point_groups_id}`,
second_name: groupsMap[apiRule.evaluation_point_groups_id?.toString() || '']?.second_name || `${apiRule.evaluation_point_groups_id}`
}
};
const rule = mapApiRuleToFrontendModel(enhancedApiRule);
// 格式化日期字段
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
* @returns 评查点详情
*/
export async function getRule(id: 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
`
};
// 获取评查点详情
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}`
}
};
// 查询评查点分组
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 评查点数据
* @returns 创建的评查点
*/
export async function createRule(ruleData: Omit<Rule, 'id' | 'createdAt' | 'updatedAt'>): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 将前端模型转换为API接受的格式
const apiRuleData = {
code: ruleData.code,
name: ruleData.name,
evaluation_point_groups_id: parseInt(ruleData.groupId),
risk: ruleData.priority === 'high' ? '高' : ruleData.priority === 'medium' ? '中' : '低',
description: ruleData.description,
is_enabled: ruleData.isActive,
// 以下是默认值,实际应用中需要根据业务逻辑设置
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);
// 检查是否有错误响应
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 评查点数据
* @returns 更新后的评查点
*/
export async function updateRule(id: string, ruleData: Partial<Omit<Rule, 'id' | 'createdAt' | 'updatedAt'>>): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 构建API接受的更新数据
const apiRuleData: Record<string, unknown> = {};
if (ruleData.code !== undefined) {
apiRuleData.code = ruleData.code;
}
if (ruleData.name !== undefined) {
apiRuleData.name = ruleData.name;
}
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);
// 检查是否有错误响应
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
* @returns 删除结果
*/
export async function deleteRule(id: string): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
try {
// console.log(`开始删除评查点, ID: ${id}`);
// 使用 PostgREST 语法,通过查询参数指定要删除的行
const postgrestParams: PostgrestParams = {
filter: {
'id': `eq.${id}`
},
headers: {
'Prefer': 'return=representation' // 请求返回被删除的记录
}
};
// 使用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
* @returns 新创建的评查点
*/
export async function duplicateRule(id: string): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 1. 获取原评查点详情
const ruleResponse = await getRule(id);
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);
} 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 reviewType 评查类型,contract表示合同,record表示卷宗
* @returns 评查点类型列表
*/
export async function getRuleTypes(reviewType?: string): Promise<{data: RuleType[]; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 构建PostgrestParams参数
const postgrestParams: PostgrestParams = {
select: `
id,
pid,
code,
name,
description,
is_enabled
`,
// 查询父ID为0的类型(顶级类型)
filter: {
'pid': 'eq.0'
}
};
// 根据 reviewType 添加过滤条件
if (reviewType === 'contract') {
// 如果是合同类型,只加载id=3的评查点类型
postgrestParams.filter!['id'] = 'eq.3';
} else if (reviewType === 'record') {
// 如果是卷宗类型,只加载id=1和id=2的评查点类型
postgrestParams.filter!['id'] = 'in.(1,2)';
}
// 发送请求获取评查点类型列表
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 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
}));
return { data: ruleTypes };
}else{
return { error: '9000接口返回数据格式不正确', status: 500 };
}
}else if(Array.isArray(response.data) && response.data.length > 0){
// console.log("评查点类型列表",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
}));
return { data: ruleTypes };
}else{
return { error: '3000接口返回数据格式不正确', status: 500 };
}
} catch (error) {
console.error('获取评查点类型出错:', error);
return {
error: error instanceof Error ? error.message : '获取评查点类型失败',
status: 500
};
}
}
/**
* 根据评查点类型ID获取规则组列表
* @param typeId 评查点类型ID
* @returns 规则组列表
*/
export async function getRuleGroupsByType(typeId: 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}`
}
};
// 发送请求获取规则组列表
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 评查点数据
*/
export async function getEvaluationPoint(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
};
}
}