feat: align frontend document and rule management flows

This commit is contained in:
wren
2026-05-06 09:40:37 +08:00
parent 8a5044b024
commit c54f84382b
41 changed files with 4239 additions and 2903 deletions
+173 -212
View File
@@ -1,6 +1,11 @@
import { postgrestGet, postgrestPost, postgrestPut, postgrestDelete, type PostgrestParams } from '../postgrest-client';
import { apiRequest } from '../axios-client';
import { formatDate } from '../../utils';
import {
getEvaluationPointGroup,
getEvaluationPointGroupChildren,
getEvaluationPointGroupsByDocumentTypes
} from './rule-groups';
/**
* 从不同格式的 API 响应中提取数据
@@ -181,6 +186,74 @@ function mapApiRuleToFrontendModel(apiRule: ApiRule): Rule {
};
}
async function enrichRuleGroupRelation(apiRule: ApiRule, token?: string): Promise<ApiRule> {
if (!apiRule.evaluation_point_groups_id || apiRule.child_group || apiRule.parent_group) {
return apiRule;
}
const groupResponse = await getEvaluationPointGroup(String(apiRule.evaluation_point_groups_id), false, token);
if (groupResponse.error || !groupResponse.data) {
return apiRule;
}
const childGroup = groupResponse.data;
const parentGroupId = childGroup.pid && childGroup.pid !== '0' ? Number(childGroup.pid) : null;
let parentGroup: ApiRule['parent_group'] = null;
if (parentGroupId) {
const parentResponse = await getEvaluationPointGroup(String(parentGroupId), false, token);
if (!parentResponse.error && parentResponse.data) {
parentGroup = {
id: Number(parentResponse.data.id),
name: parentResponse.data.name
};
}
}
return {
...apiRule,
evaluation_point_groups_pid: parentGroupId ?? apiRule.evaluation_point_groups_pid ?? null,
child_group: {
id: Number(childGroup.id),
name: childGroup.name
},
parent_group: parentGroup
};
}
async function enrichEvaluationPointGroupRelation(
point: EvaluationPointData,
token?: string
): Promise<EvaluationPointData> {
if (!point.evaluation_point_groups_id) {
return point;
}
const childResponse = await getEvaluationPointGroup(String(point.evaluation_point_groups_id), false, token);
if (childResponse.error || !childResponse.data) {
return point;
}
const childGroup = childResponse.data;
const parentGroupId = childGroup.pid && childGroup.pid !== '0' ? Number(childGroup.pid) : null;
let ruleType = point.ruleType || '';
if (parentGroupId) {
const parentResponse = await getEvaluationPointGroup(String(parentGroupId), false, token);
if (!parentResponse.error && parentResponse.data) {
ruleType = parentResponse.data.name;
}
}
return {
...point,
evaluation_point_groups_pid: parentGroupId ?? point.evaluation_point_groups_pid ?? null,
groupId: String(childGroup.id),
groupName: childGroup.name,
ruleType
};
}
/**
* 获取评查点列表
* @param params 查询参数
@@ -279,6 +352,9 @@ export async function getRulesList(params: RulesQueryParams): Promise<{data: Rul
);
if (response.error) {
if (response.status === 404) {
return await getRulesListFromPostgrest(params);
}
return { error: response.error, status: response.status };
}
@@ -334,6 +410,9 @@ export async function getRulesList(params: RulesQueryParams): Promise<{data: Rul
};
} catch (error) {
console.error('❌ 获取评查点列表出错:', error);
if (error instanceof Error && error.message.includes('404')) {
return await getRulesListFromPostgrest(params);
}
return {
error: error instanceof Error ? error.message : '获取评查点列表失败',
status: 500
@@ -341,6 +420,66 @@ export async function getRulesList(params: RulesQueryParams): Promise<{data: Rul
}
}
async function getRulesListFromPostgrest(
params: RulesQueryParams
): Promise<{data: RulesListResponse; error?: never} | {data?: never; error: string; status?: number}> {
const {
page = 1,
pageSize = 10,
ruleType,
groupId,
risk,
isActive,
keyword,
area,
documentAttributeType,
token
} = params;
const postgrestParams: PostgrestParams = {
select: 'id,code,name,area,evaluation_point_groups_id,evaluation_point_groups_pid,risk,description,is_enabled,document_attribute_type,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)',
order: 'updated_at.desc',
limit: pageSize,
offset: (page - 1) * pageSize,
token,
filter: {}
};
if (ruleType) postgrestParams.filter!.evaluation_point_groups_pid = `eq.${ruleType}`;
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 (area) postgrestParams.filter!.area = `eq.${area}`;
if (documentAttributeType) postgrestParams.filter!.document_attribute_type = `eq.${documentAttributeType}`;
if (keyword?.trim()) {
const safeKeyword = keyword.trim().replace(/,/g, ' ');
postgrestParams.or = `name.ilike.*${safeKeyword}*,code.ilike.*${safeKeyword}*`;
}
const response = await postgrestGet<{ code: number; msg: string; data: ApiRule[] } | ApiRule[]>(
'/api/postgrest/proxy/evaluation_points',
postgrestParams
);
if (response.error) {
return { error: response.error, status: response.status };
}
let rows: ApiRule[] = [];
if (Array.isArray(response.data)) {
rows = response.data;
} else if (response.data && 'data' in response.data && Array.isArray(response.data.data)) {
rows = response.data.data;
}
return {
data: {
rules: rows.map(mapApiRuleToFrontendModel),
totalCount: rows.length
}
};
}
/**
* 获取单个评查点详情
* @param id 评查点ID
@@ -403,32 +542,11 @@ export async function getRule(id: string, token?: string): Promise<{data: Rule;
return { error: '评查点不存在', status: 404 };
}
// 获取分组信息
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}[]}>('/api/postgrest/proxy/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
};
}
}
apiRule = await enrichRuleGroupRelation(apiRule, token);
} catch (error) {
console.error('获取分组信息失败:', error);
// 忽略错误,使用默认分组名
// 忽略错误,保持评查点详情主链路可用
}
// 将API返回的数据映射到前端模型
@@ -522,140 +640,24 @@ export interface RuleGroup {
*/
export async function getRuleTypes(documentTypeIds?: number[], token?: string): Promise<{data: RuleType[]; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 🔑 如果没有传入 documentTypeIds,返回空数组
if (!documentTypeIds || documentTypeIds.length === 0) {
console.warn('getRuleTypes: 未提供 documentTypeIds 参数');
return { data: [] };
}
const documentTypesParams: PostgrestParams = {
select: 'id, name, evaluation_point_groups_ids',
filter: {
// 🔑 只查询指定的文档类型 ID
'id': `in.(${documentTypeIds.join(',')})`
},
token
};
const documentTypesResponse = await postgrestGet<{
code: number;
msg: string;
data: Array<{
id: number;
name: string;
evaluation_point_groups_ids: number[];
}>
}>('/api/postgrest/proxy/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;
}>
}>('/api/postgrest/proxy/evaluation_point_groups', groupsParams);
// 检查是否有错误响应
const response = await getEvaluationPointGroupsByDocumentTypes(documentTypeIds, token);
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,
return {
data: (response.data || []).map(item => ({
id: item.id,
pid: item.pid,
code: item.code || '',
name: item.name,
description: item.description,
description: item.description || '',
isEnabled: item.is_enabled
}));
// console.log('📋 [getRuleTypes] 返回评查点类型:', ruleTypes);
return { data: ruleTypes };
} else {
return { data: [] };
}
}))
};
} catch (error) {
console.error('获取评查点类型出错:', error);
return {
@@ -673,73 +675,30 @@ export async function getRuleTypes(documentTypeIds?: number[], token?: string):
*/
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;
}>;
}>('/api/postgrest/proxy/evaluation_point_groups', postgrestParams);
// 检查是否有错误响应
const response = await getEvaluationPointGroupChildren(typeId, { pageSize: 500 }, token);
if (response.error) {
if (response.status === 404) {
return {
data: [
{ code: '通用', label: '通用' }
]
};
}
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返回的数据映射到前端模型
// console.log("评查点类型列表",response.data);
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 };
}
const ruleGroups = (response.data || []).map(item => ({
id: item.id,
name: item.name,
description: item.description,
isEnabled: item.is_enabled,
code: item.code
}));
return { data: ruleGroups };
} catch (error) {
console.error('获取规则组出错:', error);
return {
@@ -853,7 +812,7 @@ export function convertApiRuleToFormData(apiRule: ApiRule): FormattedEvaluationP
is_enabled: apiRule.is_enabled,
description: apiRule.description,
references_laws: apiRule.references_laws || null,
evaluation_point_groups_pid: apiRule.evaluation_point_groups?.first_name ? null : null,
evaluation_point_groups_pid: apiRule.parent_group?.id || apiRule.evaluation_point_groups_pid || null,
evaluation_point_groups_id: apiRule.evaluation_point_groups_id,
extraction_config: extractFields(),
evaluation_config: {
@@ -1219,8 +1178,10 @@ export async function getEvaluationPoint(
return { error: '评查点不存在', status: 404 };
}
console.log('✅ getEvaluationPoint 成功:', response.data);
return { data: response.data };
const enrichedData = await enrichEvaluationPointGroupRelation(response.data, token);
console.log('✅ getEvaluationPoint 成功:', enrichedData);
return { data: enrichedData };
} catch (error) {
console.error('❌ 获取评查点出错:', error);
return {