feat: align frontend document and rule management flows
This commit is contained in:
+96
-45
@@ -110,51 +110,44 @@ const FALLBACK_MENU_DATA: Record<string, MenuItem[]> = {
|
||||
},
|
||||
{
|
||||
id: 'rule-management',
|
||||
title: '评查规则库',
|
||||
title: '规则管理',
|
||||
path: '/rules',
|
||||
icon: 'ri-book-3-line',
|
||||
order: 4,
|
||||
children: [
|
||||
{
|
||||
id: 'rule-groups',
|
||||
title: '评查点分组',
|
||||
path: '/rule-groups',
|
||||
icon: 'ri-folder-open-line',
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
id: 'rules-list',
|
||||
title: '评查点列表',
|
||||
path: '/rules/list',
|
||||
icon: 'ri-list-check-3',
|
||||
order: 2
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
id: 'rules-file',
|
||||
title: '评查文件列表',
|
||||
path: '/rules-files',
|
||||
icon: 'ri-list-check-2',
|
||||
order: 3
|
||||
order: 2
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'contract-template',
|
||||
title: '合同模板',
|
||||
title: '合同管理',
|
||||
path: '/contract-template',
|
||||
icon: 'ri-file-search-line',
|
||||
order: 5,
|
||||
children: [
|
||||
{
|
||||
id: 'contract-search-ai',
|
||||
title: '智能搜索',
|
||||
title: '模板搜索',
|
||||
path: '/contract-template/search',
|
||||
icon: 'ri-search-line',
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
id: 'contract-list',
|
||||
title: '合同列表',
|
||||
title: '模板列表',
|
||||
path: '/contract-template/list',
|
||||
icon: 'ri-folder-line',
|
||||
order: 2
|
||||
@@ -167,31 +160,34 @@ const FALLBACK_MENU_DATA: Record<string, MenuItem[]> = {
|
||||
path: '/settings',
|
||||
icon: 'ri-settings-4-line',
|
||||
order: 6,
|
||||
requiredRole: 'developer',
|
||||
children: [
|
||||
{
|
||||
id: 'rule-groups',
|
||||
title: '规则组导航',
|
||||
path: '/rule-groups',
|
||||
icon: 'ri-folder-open-line',
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
id: 'config-lists',
|
||||
title: '配置列表',
|
||||
path: '/config-lists',
|
||||
icon: 'ri-list-check-3',
|
||||
order: 1,
|
||||
requiredRole: 'developer'
|
||||
order: 2
|
||||
},
|
||||
{
|
||||
id: 'document-types',
|
||||
title: '文档类型',
|
||||
path: '/document-types',
|
||||
icon: 'ri-file-list-line',
|
||||
order: 2,
|
||||
requiredRole: 'developer'
|
||||
order: 3
|
||||
},
|
||||
{
|
||||
id: 'prompt-management',
|
||||
title: '提示词管理',
|
||||
path: '/prompts',
|
||||
icon: 'ri-chat-1-line',
|
||||
order: 3,
|
||||
requiredRole: 'developer'
|
||||
order: 4
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -252,51 +248,44 @@ const FALLBACK_MENU_DATA: Record<string, MenuItem[]> = {
|
||||
},
|
||||
{
|
||||
id: 'rule-management',
|
||||
title: '评查规则库',
|
||||
title: '规则管理',
|
||||
path: '/rules',
|
||||
icon: 'ri-book-3-line',
|
||||
order: 4,
|
||||
children: [
|
||||
{
|
||||
id: 'rule-groups',
|
||||
title: '评查点分组',
|
||||
path: '/rule-groups',
|
||||
icon: 'ri-folder-open-line',
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
id: 'rules-list',
|
||||
title: '评查点列表',
|
||||
path: '/rules/list',
|
||||
icon: 'ri-list-check-3',
|
||||
order: 2
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
id: 'rules-file',
|
||||
title: '评查文件列表',
|
||||
path: '/rules-files',
|
||||
icon: 'ri-list-check-2',
|
||||
order: 3
|
||||
order: 2
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'contract-template',
|
||||
title: '合同模板',
|
||||
title: '合同管理',
|
||||
path: '/contract-template',
|
||||
icon: 'ri-file-search-line',
|
||||
order: 5,
|
||||
children: [
|
||||
{
|
||||
id: 'contract-search-ai',
|
||||
title: '智能搜索',
|
||||
title: '模板搜索',
|
||||
path: '/contract-template/search',
|
||||
icon: 'ri-search-line',
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
id: 'contract-list',
|
||||
title: '合同列表',
|
||||
title: '模板列表',
|
||||
path: '/contract-template/list',
|
||||
icon: 'ri-folder-line',
|
||||
order: 2
|
||||
@@ -367,14 +356,14 @@ const FALLBACK_MENU_DATA: Record<string, MenuItem[]> = {
|
||||
},
|
||||
{
|
||||
id: 'rule-management',
|
||||
title: '评查规则库',
|
||||
title: '规则管理',
|
||||
path: '/rules',
|
||||
icon: 'ri-book-3-line',
|
||||
order: 4,
|
||||
children: [
|
||||
{
|
||||
id: 'rule-groups',
|
||||
title: '评查点分组',
|
||||
title: '规则组导航',
|
||||
path: '/rule-groups',
|
||||
icon: 'ri-folder-open-line',
|
||||
order: 1
|
||||
@@ -397,21 +386,21 @@ const FALLBACK_MENU_DATA: Record<string, MenuItem[]> = {
|
||||
},
|
||||
{
|
||||
id: 'contract-template',
|
||||
title: '合同模板',
|
||||
title: '合同管理',
|
||||
path: '/contract-template',
|
||||
icon: 'ri-file-search-line',
|
||||
order: 5,
|
||||
children: [
|
||||
{
|
||||
id: 'contract-search-ai',
|
||||
title: '智能搜索',
|
||||
title: '模板搜索',
|
||||
path: '/contract-template/search',
|
||||
icon: 'ri-search-line',
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
id: 'contract-list',
|
||||
title: '合同列表',
|
||||
title: '模板列表',
|
||||
path: '/contract-template/list',
|
||||
icon: 'ri-folder-line',
|
||||
order: 2
|
||||
@@ -475,14 +464,14 @@ const FALLBACK_MENU_DATA: Record<string, MenuItem[]> = {
|
||||
},
|
||||
{
|
||||
id: 'rule-management',
|
||||
title: '评查规则库',
|
||||
title: '规则管理',
|
||||
path: '/rules',
|
||||
icon: 'ri-book-3-line',
|
||||
order: 4,
|
||||
children: [
|
||||
{
|
||||
id: 'rule-groups',
|
||||
title: '评查点分组',
|
||||
title: '规则组导航',
|
||||
path: '/rule-groups',
|
||||
icon: 'ri-folder-open-line',
|
||||
order: 1
|
||||
@@ -505,21 +494,21 @@ const FALLBACK_MENU_DATA: Record<string, MenuItem[]> = {
|
||||
},
|
||||
{
|
||||
id: 'contract-template',
|
||||
title: '合同模板',
|
||||
title: '合同管理',
|
||||
path: '/contract-template',
|
||||
icon: 'ri-file-search-line',
|
||||
order: 5,
|
||||
children: [
|
||||
{
|
||||
id: 'contract-search-ai',
|
||||
title: '智能搜索',
|
||||
title: '模板搜索',
|
||||
path: '/contract-template/search',
|
||||
icon: 'ri-search-line',
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
id: 'contract-list',
|
||||
title: '合同列表',
|
||||
title: '模板列表',
|
||||
path: '/contract-template/list',
|
||||
icon: 'ri-folder-line',
|
||||
order: 2
|
||||
@@ -997,7 +986,7 @@ function convertBackendRoutesToMenuItems(backendRoutes: BackendRouteInfo[], incl
|
||||
// console.log('🔄 [convertBackendRoutesToMenuItems] 转换完成,返回的菜单项数量:', result.length);
|
||||
// console.log('🔄 [convertBackendRoutesToMenuItems] 返回的菜单数据:', JSON.stringify(result, null, 2));
|
||||
|
||||
return result;
|
||||
return normalizeMenuStructure(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -1038,7 +1027,69 @@ function buildFallbackRoutes(roleKey: string): {
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: fallbackMenus.filter(item => isMinimalMenuPath(item.path)),
|
||||
data: normalizeMenuStructure(fallbackMenus.filter(item => isMinimalMenuPath(item.path))),
|
||||
permissionMap,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeMenuStructure(menuItems: MenuItem[]): MenuItem[] {
|
||||
const clonedMenuItems = menuItems.map(item => ({
|
||||
...item,
|
||||
children: item.children ? normalizeMenuStructure(item.children) : undefined,
|
||||
}));
|
||||
|
||||
const collectDescendantPaths = (items: MenuItem[] | undefined): string[] => {
|
||||
if (!items || items.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return items.flatMap((item) => [
|
||||
item.path,
|
||||
...collectDescendantPaths(item.children),
|
||||
]);
|
||||
};
|
||||
|
||||
const nestedPathSet = new Set(
|
||||
clonedMenuItems.flatMap(item => collectDescendantPaths(item.children)),
|
||||
);
|
||||
|
||||
const dedupedTopLevelItems = clonedMenuItems.filter(item => !nestedPathSet.has(item.path));
|
||||
|
||||
const ruleManagement = dedupedTopLevelItems.find(item => item.path === '/rules');
|
||||
const systemSettings = dedupedTopLevelItems.find(item => item.path === '/settings');
|
||||
const syntheticRuleGroupsMenu: MenuItem = {
|
||||
id: 'rule-groups',
|
||||
title: '规则组导航',
|
||||
path: '/rule-groups',
|
||||
icon: 'ri-folder-open-line',
|
||||
order: 1,
|
||||
};
|
||||
|
||||
let ruleGroupsMenu: MenuItem = syntheticRuleGroupsMenu;
|
||||
|
||||
if (ruleManagement?.children?.length) {
|
||||
const ruleGroupIndex = ruleManagement.children.findIndex(child => child.path === '/rule-groups');
|
||||
if (ruleGroupIndex !== -1) {
|
||||
const [existingRuleGroupsMenu] = ruleManagement.children.splice(ruleGroupIndex, 1);
|
||||
ruleGroupsMenu = existingRuleGroupsMenu;
|
||||
ruleManagement.children = ruleManagement.children
|
||||
.map((child, index) => ({ ...child, order: index + 1 }))
|
||||
.sort((a, b) => a.order - b.order);
|
||||
}
|
||||
}
|
||||
|
||||
if (!systemSettings) {
|
||||
return dedupedTopLevelItems;
|
||||
}
|
||||
|
||||
const settingsChildren = systemSettings.children ? [...systemSettings.children] : [];
|
||||
if (!settingsChildren.some(child => child.path === '/rule-groups')) {
|
||||
settingsChildren.unshift({ ...ruleGroupsMenu, order: 1 });
|
||||
}
|
||||
|
||||
systemSettings.children = settingsChildren
|
||||
.map((child, index) => ({ ...child, order: index + 1 }))
|
||||
.sort((a, b) => a.order - b.order);
|
||||
|
||||
return dedupedTopLevelItems;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ export async function getDocumentTypes(
|
||||
pageSize: searchParams.pageSize || 50,
|
||||
};
|
||||
if (searchParams.ids) params.ids = searchParams.ids.join(",");
|
||||
if (searchParams.entry_module_id) params.entry_module_id = searchParams.entry_module_id;
|
||||
|
||||
const response = await axios.get(`${API_BASE_URL}/api/document-types`, {
|
||||
params,
|
||||
|
||||
@@ -2,6 +2,13 @@ import { postgrestGet, postgrestPut, type PostgrestParams } from '../postgrest-c
|
||||
import { apiRequest } from '../axios-client';
|
||||
import { formatDate } from '../../utils';
|
||||
|
||||
function buildMissingRuleGroupApiError(): { error: string; status: number } {
|
||||
return {
|
||||
error: '评查点分组接口未部署:后端 `GET /api/v3/evaluation-point-groups` 当前返回 404。',
|
||||
status: 404
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 评查点分组接口
|
||||
*/
|
||||
@@ -252,6 +259,9 @@ export async function getEvaluationPointGroups(
|
||||
|
||||
|
||||
if (response.error) {
|
||||
if (response.status === 404) {
|
||||
return buildMissingRuleGroupApiError();
|
||||
}
|
||||
console.error('❌ getEvaluationPointGroups 错误:', response.error);
|
||||
return { error: response.error, status: response.status };
|
||||
}
|
||||
@@ -274,8 +284,12 @@ export async function getEvaluationPointGroups(
|
||||
} catch (error) {
|
||||
console.error('❌ 获取一级分组列表出错:', error);
|
||||
return {
|
||||
error: error instanceof Error ? error.message : '获取一级分组列表失败',
|
||||
status: 500
|
||||
...(error instanceof Error && error.message.includes('404')
|
||||
? buildMissingRuleGroupApiError()
|
||||
: {
|
||||
error: error instanceof Error ? error.message : '获取一级分组列表失败',
|
||||
status: 500
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -305,6 +319,9 @@ export async function getAllEvaluationPointGroups(
|
||||
});
|
||||
|
||||
if (response.error) {
|
||||
if (response.status === 404) {
|
||||
return buildMissingRuleGroupApiError();
|
||||
}
|
||||
return { error: response.error, status: response.status };
|
||||
}
|
||||
|
||||
@@ -337,6 +354,49 @@ export async function getAllEvaluationPointGroups(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按文档类型范围获取可用评查点分组(树形结构)
|
||||
*/
|
||||
export async function getEvaluationPointGroupsByDocumentTypes(
|
||||
documentTypeIds: number[],
|
||||
token?: string
|
||||
): Promise<{data: RuleGroup[]; error?: never} | {data?: never; error: string; status?: number}> {
|
||||
try {
|
||||
if (!documentTypeIds || documentTypeIds.length === 0) {
|
||||
return { data: [] };
|
||||
}
|
||||
|
||||
const queryParams = new URLSearchParams();
|
||||
queryParams.append('document_type_ids', documentTypeIds.join(','));
|
||||
queryParams.append('include_disabled', 'false');
|
||||
queryParams.append('with_rule_count', 'false');
|
||||
|
||||
const response = await apiRequest<EvaluationPointGroupResponse[]>(
|
||||
`/api/v3/evaluation-point-groups/by-document-types?${queryParams.toString()}`,
|
||||
{
|
||||
method: 'GET',
|
||||
...(token ? { headers: { 'Authorization': `Bearer ${token}` } } : {})
|
||||
}
|
||||
);
|
||||
|
||||
if (response.error) {
|
||||
return { error: response.error, status: response.status };
|
||||
}
|
||||
|
||||
if (response.data && Array.isArray(response.data)) {
|
||||
return { data: response.data.map(convertApiGroupToRuleGroup) };
|
||||
}
|
||||
|
||||
return { error: '获取文档类型可用分组失败:返回数据格式不正确', status: 500 };
|
||||
} catch (error) {
|
||||
console.error('❌ 获取文档类型可用分组出错:', error);
|
||||
return {
|
||||
error: error instanceof Error ? error.message : '获取文档类型可用分组失败',
|
||||
status: 500
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 3. 获取单个分组详情(FastAPI v3)
|
||||
* @param id 分组ID
|
||||
|
||||
+173
-212
@@ -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 {
|
||||
|
||||
@@ -65,6 +65,8 @@ export interface DocumentUI {
|
||||
documentNumber: string;
|
||||
type: string;
|
||||
typeName: string;
|
||||
groupId?: number | null;
|
||||
groupName?: string | null;
|
||||
size: number;
|
||||
auditStatus: number; // -1: 不通过, 0: 待审核, 1: 通过, 2: 警告, 3: 审核中
|
||||
fileStatus: string; // Waiting, Cutting, Extractioning, Failed, Evaluationing, Processed
|
||||
@@ -106,6 +108,8 @@ export interface DocumentVersionUI {
|
||||
documentNumber: string;
|
||||
type: string;
|
||||
typeName: string;
|
||||
groupId?: number | null;
|
||||
groupName?: string | null;
|
||||
size: number;
|
||||
auditStatus: number;
|
||||
fileStatus: string;
|
||||
@@ -152,6 +156,9 @@ interface LeauditListItem {
|
||||
previousVersionId?: number | null;
|
||||
typeId?: number | null;
|
||||
typeCode?: string | null;
|
||||
typeName?: string | null;
|
||||
groupId?: number | null;
|
||||
groupName?: string | null;
|
||||
region: string;
|
||||
normalizedName?: string | null;
|
||||
fileId?: number | null;
|
||||
@@ -168,6 +175,9 @@ interface LeauditListItem {
|
||||
passedCount?: number | null;
|
||||
failedCount?: number | null;
|
||||
skippedCount?: number | null;
|
||||
documentNumber?: string | null;
|
||||
auditStatus?: number | null;
|
||||
isTestDocument?: boolean | null;
|
||||
updatedAt?: string | null;
|
||||
hasHistory?: boolean;
|
||||
totalVersions?: number;
|
||||
@@ -279,7 +289,9 @@ function mapHistoryVersionToUI(history: LeauditHistoryVersion, source: LeauditLi
|
||||
name: history.fileName || source.fileName || source.normalizedName || '未命名文档',
|
||||
documentNumber: buildDocumentNumber(history),
|
||||
type: source.typeId?.toString() || '',
|
||||
typeName: typeNameFromCode(source.typeCode),
|
||||
typeName: source.typeName || typeNameFromCode(source.typeCode),
|
||||
groupId: source.groupId ?? null,
|
||||
groupName: source.groupName ?? null,
|
||||
size: 0,
|
||||
auditStatus: mapLeauditDocToAuditStatus({
|
||||
processingStatus: history.processingStatus,
|
||||
@@ -316,7 +328,9 @@ function mapLeauditDocumentToUI(doc: LeauditListItem | LeauditDocumentDetail): D
|
||||
name: doc.fileName || doc.normalizedName || '未命名文档',
|
||||
documentNumber: ('documentNumber' in doc && doc.documentNumber) ? doc.documentNumber : buildDocumentNumber(doc),
|
||||
type: doc.typeId?.toString() || '',
|
||||
typeName: typeNameFromCode(doc.typeCode),
|
||||
typeName: doc.typeName || typeNameFromCode(doc.typeCode),
|
||||
groupId: doc.groupId ?? null,
|
||||
groupName: doc.groupName ?? null,
|
||||
size: doc.fileSize || 0,
|
||||
auditStatus: ('auditStatus' in doc && doc.auditStatus !== null && doc.auditStatus !== undefined)
|
||||
? doc.auditStatus
|
||||
@@ -778,6 +792,7 @@ export async function getDocumentsListFromAPI(searchParams: {
|
||||
name?: string;
|
||||
documentNumber?: string;
|
||||
documentTypeIds?: number[]; // 文档类型ID数组
|
||||
entryModuleId?: number;
|
||||
auditStatus?: string;
|
||||
fileStatus?: string;
|
||||
dateFrom?: string;
|
||||
@@ -795,6 +810,7 @@ export async function getDocumentsListFromAPI(searchParams: {
|
||||
name,
|
||||
documentNumber,
|
||||
documentTypeIds,
|
||||
entryModuleId,
|
||||
auditStatus,
|
||||
fileStatus,
|
||||
dateFrom,
|
||||
@@ -824,11 +840,13 @@ export async function getDocumentsListFromAPI(searchParams: {
|
||||
params.type_ids = documentTypeIds.join(',');
|
||||
}
|
||||
|
||||
// 下面几个旧筛选项暂未完全对齐:
|
||||
// - documentNumber
|
||||
// - auditStatus
|
||||
void documentNumber;
|
||||
void auditStatus;
|
||||
if (entryModuleId && entryModuleId > 0) {
|
||||
params.entry_module_id = entryModuleId;
|
||||
}
|
||||
if (documentNumber) params.documentNumber = documentNumber;
|
||||
if (auditStatus !== undefined && auditStatus !== "") {
|
||||
params.auditStatus = Number(auditStatus);
|
||||
}
|
||||
if (dateFrom) params.dateFrom = dateFrom;
|
||||
if (dateTo) params.dateTo = dateTo;
|
||||
|
||||
|
||||
+160
-14
@@ -151,6 +151,21 @@ export interface DocumentType {
|
||||
ruleSetIds?: number[];
|
||||
}
|
||||
|
||||
export interface DocumentSubtypeGroup {
|
||||
id: number;
|
||||
name: string;
|
||||
code: string;
|
||||
documentTypeId: number;
|
||||
documentTypeName?: string | null;
|
||||
rootGroupId?: number | null;
|
||||
rootGroupName?: string | null;
|
||||
entryModuleName?: string | null;
|
||||
entryModuleId?: number | null;
|
||||
isDefault?: boolean;
|
||||
displayName?: string;
|
||||
displayHint?: string;
|
||||
}
|
||||
|
||||
export interface UploadErrorDetails {
|
||||
title: string;
|
||||
summary: string;
|
||||
@@ -211,6 +226,7 @@ export interface UploadResult {
|
||||
fileName: string;
|
||||
fileSize: number;
|
||||
typeId: number;
|
||||
groupId?: number | null;
|
||||
region: string;
|
||||
processingStatus: string;
|
||||
duplicateUpload: boolean;
|
||||
@@ -236,6 +252,7 @@ interface NewUploadResponse {
|
||||
fileId: number;
|
||||
typeId: number;
|
||||
typeCode: string;
|
||||
groupId?: number | null;
|
||||
region: string;
|
||||
fileName: string;
|
||||
ossUrl: string;
|
||||
@@ -373,7 +390,7 @@ export function buildUploadErrorDetails(
|
||||
detailLines,
|
||||
actionLines: [
|
||||
'到“系统设置 / 文档类型管理”检查该文档类型是否绑定了正确的规则集。',
|
||||
'到“规则管理 / 规则集管理”确认对应规则集的可用规则数是否正常。',
|
||||
'到“规则管理”确认对应规则集的可用规则数是否正常。',
|
||||
'如果首页入口也异常,请同时到“系统设置 / 入口模块管理”检查入口模块绑定。',
|
||||
],
|
||||
rawMessage: message,
|
||||
@@ -395,7 +412,7 @@ export function buildUploadErrorDetails(
|
||||
summary: '当前上传入口关联的规则集不可用,文件无法开始审核。',
|
||||
detailLines,
|
||||
actionLines: [
|
||||
'到“规则管理 / 规则集管理”检查对应规则集是否存在、可用规则数是否正常。',
|
||||
'到“规则管理”检查对应规则集是否存在、可用规则数是否正常。',
|
||||
'如文档类型绑定了错误的规则集,请到“系统设置 / 文档类型管理”修正绑定关系。',
|
||||
],
|
||||
rawMessage: message,
|
||||
@@ -595,15 +612,12 @@ export async function appendContractAttachments(
|
||||
formData.append('files', file);
|
||||
});
|
||||
|
||||
// 添加其他参数
|
||||
formData.append('merge_mode', mergeMode);
|
||||
formData.append('is_reprocess', isReprocess.toString());
|
||||
if (remark) {
|
||||
formData.append('remark', remark);
|
||||
}
|
||||
|
||||
// 新链路仅保留附件追加;mergeMode / remark 在后端暂不消费,但继续保留函数签名兼容旧页面调用。
|
||||
void mergeMode;
|
||||
void remark;
|
||||
|
||||
// 构建请求URL
|
||||
const uploadUrl = `${UPLOAD_URL}/contracts/${documentId}/append_attachments`;
|
||||
const uploadUrl = `${API_BASE_URL}/api/documents/${documentId}/attachments`;
|
||||
console.log('【合同附件追加】准备发送请求到服务器:', uploadUrl);
|
||||
|
||||
// 设置请求头
|
||||
@@ -627,11 +641,28 @@ export async function appendContractAttachments(
|
||||
const result = response.data;
|
||||
console.log('【合同附件追加】服务器返回结果:', result);
|
||||
|
||||
if (result.success) {
|
||||
return { data: result.result };
|
||||
} else {
|
||||
return { error: result.error || '附件追加失败' };
|
||||
if (result?.data) {
|
||||
if (isReprocess) {
|
||||
await axios.post(
|
||||
`${API_BASE_URL}/api/audit/run`,
|
||||
{
|
||||
documentId,
|
||||
force: true,
|
||||
speed: 'normal',
|
||||
},
|
||||
{ headers }
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
data: {
|
||||
success: true,
|
||||
result: result.data,
|
||||
error: null,
|
||||
}
|
||||
};
|
||||
}
|
||||
return { error: result?.message || result?.msg || '附件追加失败' };
|
||||
|
||||
} catch (error) {
|
||||
console.error('【合同附件追加】上传过程中发生错误:', error);
|
||||
@@ -646,8 +677,10 @@ export async function uploadDocumentToServer(
|
||||
fileName: string,
|
||||
fileType: string,
|
||||
typeId: number,
|
||||
groupId?: number | null,
|
||||
region: string = "default",
|
||||
createdBy?: number,
|
||||
attachments?: File[],
|
||||
autoRun: boolean = true,
|
||||
speed: string = "normal",
|
||||
jwtToken?: string,
|
||||
@@ -657,6 +690,12 @@ export async function uploadDocumentToServer(
|
||||
const blob = new Blob([binaryData], { type: fileType });
|
||||
formData.append("file", blob, fileName);
|
||||
formData.append("typeId", String(typeId));
|
||||
if (groupId) {
|
||||
formData.append("groupId", String(groupId));
|
||||
}
|
||||
(attachments || []).forEach((attachment) => {
|
||||
formData.append("attachments", attachment);
|
||||
});
|
||||
formData.append("region", region);
|
||||
formData.append("fileRole", "primary");
|
||||
if (createdBy !== undefined) {
|
||||
@@ -689,6 +728,7 @@ export async function uploadDocumentToServer(
|
||||
fileName: uploadData.fileName,
|
||||
fileSize: binaryData.byteLength,
|
||||
typeId: uploadData.typeId,
|
||||
groupId: uploadData.groupId,
|
||||
region: uploadData.region,
|
||||
processingStatus: uploadData.processingStatus,
|
||||
duplicateUpload: uploadData.duplicateUpload,
|
||||
@@ -819,6 +859,112 @@ export async function getDocumentTypes(token?: string): Promise<{data: DocumentT
|
||||
}
|
||||
}
|
||||
|
||||
function mapSubtypeChild(child: any, root?: any): DocumentSubtypeGroup {
|
||||
const rawName = typeof child.name === "string" ? child.name.trim() : "";
|
||||
const rawCode = typeof child.code === "string" ? child.code.trim() : "";
|
||||
const isDefault = rawName === "通用" || rawCode.endsWith(".default");
|
||||
const entryModuleId = child.entry_module_id ?? root?.entry_module_id ?? null;
|
||||
const entryModuleName = child.entry_module_name ?? root?.entry_module_name ?? null;
|
||||
const rootGroupName = root?.name ?? null;
|
||||
|
||||
return {
|
||||
id: child.id,
|
||||
name: child.name,
|
||||
code: child.code,
|
||||
documentTypeId: child.document_type_id,
|
||||
documentTypeName: child.document_type_name,
|
||||
rootGroupId: root?.id ?? null,
|
||||
rootGroupName,
|
||||
entryModuleId: typeof entryModuleId === "number" ? entryModuleId : null,
|
||||
entryModuleName,
|
||||
isDefault,
|
||||
displayName: isDefault ? `默认子类型(${rawName || "通用"})` : rawName || child.name,
|
||||
displayHint: [rootGroupName, child.document_type_name, entryModuleName, rawCode].filter(Boolean).join(" · "),
|
||||
};
|
||||
}
|
||||
|
||||
function dedupeSubtypeGroups(groups: DocumentSubtypeGroup[]): DocumentSubtypeGroup[] {
|
||||
const groupMap = new Map<number, DocumentSubtypeGroup>();
|
||||
groups.forEach((group) => {
|
||||
const existing = groupMap.get(group.id);
|
||||
if (!existing) {
|
||||
groupMap.set(group.id, group);
|
||||
return;
|
||||
}
|
||||
const currentScore = (group.rootGroupName ? 2 : 0) + (group.entryModuleId ? 1 : 0);
|
||||
const existingScore = (existing.rootGroupName ? 2 : 0) + (existing.entryModuleId ? 1 : 0);
|
||||
if (currentScore > existingScore) {
|
||||
groupMap.set(group.id, group);
|
||||
}
|
||||
});
|
||||
return Array.from(groupMap.values());
|
||||
}
|
||||
|
||||
export async function getDocumentSubtypeGroups(
|
||||
documentTypeId: number,
|
||||
token?: string,
|
||||
entryModuleId?: number | null,
|
||||
): Promise<{ data: DocumentSubtypeGroup[]; error?: never } | { data?: never; error: string; status?: number }> {
|
||||
try {
|
||||
const headers: Record<string, string> = {};
|
||||
if (token) {
|
||||
headers["Authorization"] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
const allResponse = await axios.get(`${API_BASE_URL}/api/v3/evaluation-point-groups/all`, {
|
||||
params: {
|
||||
include_disabled: false,
|
||||
with_rule_count: false,
|
||||
},
|
||||
headers,
|
||||
});
|
||||
const allRoots = extractApiData<any[]>(allResponse.data) || [];
|
||||
const matchedFromTree = allRoots.flatMap((root: any) => {
|
||||
if (!Array.isArray(root?.children)) return [];
|
||||
if (entryModuleId && Number(root?.entry_module_id || 0) !== Number(entryModuleId)) {
|
||||
return [];
|
||||
}
|
||||
return root.children
|
||||
.filter((child: any) => Number(child?.document_type_id || 0) === Number(documentTypeId))
|
||||
.map((child: any) => mapSubtypeChild(child, root));
|
||||
});
|
||||
|
||||
if (matchedFromTree.length > 0) {
|
||||
return { data: dedupeSubtypeGroups(matchedFromTree) };
|
||||
}
|
||||
|
||||
const response = await axios.get(`${API_BASE_URL}/api/v3/evaluation-point-groups/by-document-types`, {
|
||||
params: {
|
||||
document_type_ids: String(documentTypeId),
|
||||
include_disabled: false,
|
||||
with_rule_count: false,
|
||||
},
|
||||
headers,
|
||||
});
|
||||
const roots = extractApiData<any[]>(response.data) || [];
|
||||
const filteredRoots = entryModuleId
|
||||
? roots.filter((root: any) => Number(root?.entry_module_id || 0) === Number(entryModuleId))
|
||||
: roots;
|
||||
const fallbackRoots = filteredRoots.length > 0 ? filteredRoots : roots;
|
||||
const groups = dedupeSubtypeGroups(
|
||||
fallbackRoots.flatMap((root: any) =>
|
||||
Array.isArray(root?.children)
|
||||
? root.children
|
||||
.filter((child: any) => Number(child?.document_type_id || 0) === Number(documentTypeId))
|
||||
.map((child: any) => mapSubtypeChild(child, root))
|
||||
: [],
|
||||
),
|
||||
);
|
||||
return { data: groups };
|
||||
} catch (error) {
|
||||
console.error("获取子类型分组失败:", error);
|
||||
return {
|
||||
error: error instanceof Error ? error.message : "获取子类型分组失败",
|
||||
status: 500,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定文档的状态
|
||||
* @param documentIds 文档ID列表
|
||||
|
||||
Reference in New Issue
Block a user