feat(iit): V3.2 data consistency + project isolation + admin config redesign + Chinese labels
Summary: - Refactor timeline API to read from qc_field_status (SSOT) instead of qc_logs - Add field-issues paginated API with severity/dimension/recordId filters - Add LEFT JOIN field_metadata + qc_event_status for Chinese display names - Implement per-project ChatOrchestrator cache and SessionMemory isolation - Redesign admin IIT config tabs (REDCap -> Fields -> KB -> Rules -> Members) - Add AI-powered QC rule generation (D3 programmatic + D1/D5/D6 LLM-based) - Add clickable warning/critical detail Modal in ReportsPage - Auto-dispatch eQuery after batch QC via DailyQcOrchestrator - Update module status documentation to v3.2 Backend changes: - iitQcCockpitController: rewrite getTimeline from qc_field_status, add getFieldIssues - iitQcCockpitRoutes: add field-issues route - ChatOrchestrator: per-projectId cached instances - SessionMemory: keyed by userId::projectId - WechatCallbackController: resolve projectId from iitUserMapping - iitRuleSuggestionService: dimension-based suggest + generateD3Rules - iitBatchController: call DailyQcOrchestrator after batch QC Frontend changes: - AiStreamPage: adapt to new timeline structure with dimension tags - ReportsPage: clickable stats cards with issue detail Modal - IitProjectDetailPage: reorder tabs, add AI rule generation UI - iitProjectApi: add TimelineIssue, FieldIssueItem types and APIs Status: TypeScript compilation verified, no new lint errors Made-with: Cursor
This commit is contained in:
@@ -152,8 +152,52 @@ class ModuleService {
|
||||
});
|
||||
});
|
||||
|
||||
// 6. 合并所有模块(去重)
|
||||
const moduleSet = new Set(tenantModulesData.map(tm => tm.module_code));
|
||||
// 5.5 查询用户级别的模块权限(精细化控制)
|
||||
const userModulesData = await prisma.user_modules.findMany({
|
||||
where: {
|
||||
user_id: userId,
|
||||
tenant_id: { in: tenantIds },
|
||||
},
|
||||
select: {
|
||||
tenant_id: true,
|
||||
module_code: true,
|
||||
is_enabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
// 按租户分组 user_modules
|
||||
const userModulesByTenant = new Map<string, Map<string, boolean>>();
|
||||
for (const um of userModulesData) {
|
||||
if (!userModulesByTenant.has(um.tenant_id)) {
|
||||
userModulesByTenant.set(um.tenant_id, new Map());
|
||||
}
|
||||
userModulesByTenant.get(um.tenant_id)!.set(um.module_code, um.is_enabled);
|
||||
}
|
||||
|
||||
// 6. 合并所有模块(去重),尊重 user_modules 精细化配置
|
||||
const moduleSet = new Set<string>();
|
||||
|
||||
for (const tm of tenantModulesData) {
|
||||
const userModulesForTenant = userModulesByTenant.get(tm.tenant_id);
|
||||
if (userModulesForTenant && userModulesForTenant.size > 0) {
|
||||
const isEnabled = userModulesForTenant.get(tm.module_code);
|
||||
if (isEnabled) {
|
||||
moduleSet.add(tm.module_code);
|
||||
}
|
||||
} else {
|
||||
moduleSet.add(tm.module_code);
|
||||
}
|
||||
}
|
||||
|
||||
// 6.5 补充用户级独立配置的模块(如 AIA_PROTOCOL,租户未订阅但用户单独开通)
|
||||
for (const [, userModuleMap] of userModulesByTenant) {
|
||||
for (const [moduleCode, isEnabled] of userModuleMap) {
|
||||
if (isEnabled) {
|
||||
moduleSet.add(moduleCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const allModuleCodes = Array.from(moduleSet);
|
||||
|
||||
// 7. 获取模块详细信息
|
||||
|
||||
Reference in New Issue
Block a user