合并评查点新增代码
This commit is contained in:
@@ -1,6 +1,27 @@
|
||||
import { postgrestGet, postgrestPost, postgrestPut, postgrestDelete, type PostgrestParams } from '../postgrest-client';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
/**
|
||||
* 从不同格式的 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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 评查点列表查询参数
|
||||
*/
|
||||
@@ -927,4 +948,509 @@ export async function getRuleGroupsByType(typeId: string): Promise<{data: RuleGr
|
||||
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
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -51,4 +51,83 @@ export async function uploadFileToServer(
|
||||
} catch (error) {
|
||||
return { success: false, error: error instanceof Error ? error.message : '上传失败' };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件到文档审核系统
|
||||
*/
|
||||
export async function uploadDocumentToServer(
|
||||
binaryData: ArrayBuffer,
|
||||
fileName: string,
|
||||
fileType: string,
|
||||
typeId: string | number,
|
||||
priority: string,
|
||||
documentNumber?: string | null,
|
||||
remark?: string | null,
|
||||
isTestDocument: boolean = false
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
result?: {
|
||||
id: number;
|
||||
file_name: string;
|
||||
file_size: number;
|
||||
file_url: string;
|
||||
type_id: number;
|
||||
type_description: string;
|
||||
document_number: string | null;
|
||||
storage_type: string;
|
||||
is_test_document: boolean;
|
||||
remark: string | null;
|
||||
background_processing: boolean;
|
||||
evaluation_level: string;
|
||||
};
|
||||
error: string | null;
|
||||
}> {
|
||||
try {
|
||||
// 创建FormData对象
|
||||
const formData = new FormData();
|
||||
|
||||
// 将二进制数据转换为Blob并添加到FormData
|
||||
const blob = new Blob([binaryData], { type: fileType });
|
||||
formData.append('file', blob, fileName);
|
||||
|
||||
// 将信息添加到一个JSON对象中
|
||||
const uploadInfo = {
|
||||
type_id: Number(typeId),
|
||||
evaluation_level: priority,
|
||||
document_number: documentNumber || null,
|
||||
remark: remark || null,
|
||||
is_test_document: isTestDocument
|
||||
};
|
||||
|
||||
// 添加JSON字符串到FormData
|
||||
formData.append('upload_info', JSON.stringify(uploadInfo));
|
||||
|
||||
// 发送请求
|
||||
const response = await fetch('http://172.16.0.55:8000/admin/documents/upload', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-File-Name': encodeURIComponent(fileName)
|
||||
},
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
console.error(`上传失败 (${response.status}): ${errorText}`);
|
||||
return {
|
||||
success: false,
|
||||
error: `上传失败: ${response.status} ${response.statusText}`
|
||||
};
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('上传错误:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : '上传失败'
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -503,7 +503,7 @@ function preprocessData(data: Record<string, unknown>): Record<string, unknown>
|
||||
export async function postgrestPut<T, D extends object>(
|
||||
endpoint: string,
|
||||
data: D,
|
||||
filters?: Record<string, string>
|
||||
filters?: Record<string | number, string | number>
|
||||
): Promise<{data: T; error?: never} | {data?: never; error: string; status?: number}> {
|
||||
try {
|
||||
// 确保端点没有前导斜杠
|
||||
|
||||
Reference in New Issue
Block a user