import { postgrestGet, type PostgrestParams } from "../postgrest-client"; import dayjs from 'dayjs'; /** * 从不同格式的 API 响应中提取数据 * @param responseData API 响应数据 * @returns 提取后的数据或 null */ function extractApiData(responseData: unknown): T | null { if (!responseData) { console.warn('API响应数据为空'); return null; } try { // 检查是否有错误信息 if (typeof responseData === 'object' && responseData !== null) { // 错误检查: 检查错误码,一般成功的错误码是0或200 if ('code' in responseData) { const code = (responseData as { code: number }).code; // 如果有错误码且不是成功状态 if (code !== 0 && code !== 200) { const errorMsg = 'msg' in responseData ? (responseData as { msg: string }).msg : '未知错误'; console.error(`API响应错误: [${code}] ${errorMsg}`); return null; } } // 错误检查: 检查是否包含错误消息但没有数据 if ('error' in responseData && (responseData as { error: unknown }).error) { const error = (responseData as { error: unknown }).error; console.error(`API响应包含错误: ${typeof error === 'string' ? error : JSON.stringify(error)}`); return null; } // 格式1: { code: number, msg: string, data: T } if ('data' in responseData) { const data = (responseData as { data: unknown }).data; if (!data) { console.warn('API响应中的data字段为空'); return null; } return data as T; } } // 格式2: 直接是数据对象 return responseData as T; } catch (error) { console.error('处理API响应数据时出错:', error); return null; } } /** * 首页数据统计响应类型 */ interface HomeStatistics { todayPendingFiles: number; monthlyReviewedFiles: number; monthlyReviewGrowth: { value: number; isUp: boolean; }; monthlyPassRate: number; passRateGrowth: { value: number; isUp: boolean; }; issuesDetected: number; issuesGrowth: { value: number; isUp: boolean; }; } /** * 通过传入的 reviewType 参数构建类型过滤条件 * @param reviewType 文档类型 * @returns 过滤条件字符串 */ function buildTypeFilter(reviewType: string | null): string { let typeFilter = ''; if (reviewType === 'contract') { typeFilter = 'type_id.eq.1'; } else if (reviewType === 'record') { typeFilter = '(type_id.eq.2,type_id.eq.3)'; } return typeFilter; } /** * 获取主页数据 * @param reviewType 从客户端传入的 reviewType 值 * @returns 主页数据 */ export async function getHomeData(reviewType?: string | null): Promise { try { // 获取当前日期和时间相关值 const startOfToday = dayjs().startOf('day').format('YYYY-MM-DD HH:mm:ss'); const startOfThisMonth = dayjs().startOf('month').format('YYYY-MM-DD HH:mm:ss'); const endOfThisMonth = dayjs().endOf('month').format('YYYY-MM-DD HH:mm:ss'); const startOfLastMonth = dayjs().subtract(1, 'month').startOf('month').format('YYYY-MM-DD HH:mm:ss'); const endOfLastMonth = dayjs().subtract(1, 'month').endOf('month').format('YYYY-MM-DD HH:mm:ss'); // console.log('传入的 reviewType', reviewType); // 基于 reviewType 构建类型过滤条件 const typeFilter = buildTypeFilter(reviewType || null); // console.log('构建的 typeFilter', typeFilter); // 通用API响应处理函数 const handleApiResponse = async ( apiCall: Promise<{ data?: unknown; headers?: Record; error?: string; status?: number }>, errorMessage: string, defaultValue: T ): Promise => { try { const response = await apiCall; if (response.error) { console.error(`${errorMessage}: ${response.error}`); return defaultValue; } const data = extractApiData(response.data); if (!data) { console.warn(`${errorMessage}: 无法提取有效数据`); return defaultValue; } return data; } catch (error) { console.error(`${errorMessage}: ${error instanceof Error ? error.message : '未知错误'}`); return defaultValue; } }; // 1. 今日待审核文件 - 获取今天的待审核文件数量 (audit_status = 0 或 2) const todayPendingParams: PostgrestParams = { select: 'count', filter: { or: `(audit_status.eq.0,audit_status.eq.2,audit_status.is.null)`, created_at: `gte.${startOfToday}`, is_test_document: `eq.false` } }; // 添加类型过滤条件 if (typeFilter) { if (typeFilter.startsWith('(')) { // 确保 filter 已初始化 if (!todayPendingParams.filter) { todayPendingParams.filter = {}; } todayPendingParams.filter.or = typeFilter + ',' + todayPendingParams.filter.or; } else { const [field, op, value] = typeFilter.split('.'); if (!todayPendingParams.filter) { todayPendingParams.filter = {}; } todayPendingParams.filter[field] = `${op}.${value}`; } } const todayPendingCount = await handleApiResponse<{ count: number }[]>( postgrestGet('documents', todayPendingParams), '获取今日待审核文件数量失败', [] ); const todayPendingFiles = todayPendingCount[0]?.count || 0; // 2. 本月已审核文件 - 获取本月已审核文件数量 (audit_status != 0 且 != 2) const thisMonthReviewedParams: PostgrestParams = { select: 'count', filter: { and: `(audit_status.neq.0,audit_status.neq.2)`, updated_at: `gte.${startOfThisMonth}`, is_test_document: `eq.false` } }; // 添加类型过滤条件 if (typeFilter) { if (typeFilter.startsWith('(')) { thisMonthReviewedParams.or = typeFilter; } else { const [field, op, value] = typeFilter.split('.'); if (!thisMonthReviewedParams.filter) { thisMonthReviewedParams.filter = {}; } thisMonthReviewedParams.filter[field] = `${op}.${value}`; } } const thisMonthReviewedCount = await handleApiResponse<{ count: number }[]>( postgrestGet('documents', thisMonthReviewedParams), '获取本月已审核文件数量失败', [] ); // 本月已审核文件数量 const monthlyReviewedFiles = thisMonthReviewedCount[0]?.count || 0; // 上月已审核文件 const lastMonthReviewedParams: PostgrestParams = { select: 'count', filter: { or: `(audit_status.eq.1,audit_status.eq.-1)`, and: `(updated_at.gte.${startOfLastMonth},updated_at.lte.${endOfLastMonth})`, is_test_document: `eq.false` } }; // 添加类型过滤条件 if (typeFilter) { if (typeFilter.startsWith('(')) { // 确保 filter 已初始化 if (!lastMonthReviewedParams.filter) { lastMonthReviewedParams.filter = {}; } lastMonthReviewedParams.filter.or = lastMonthReviewedParams.filter.or + ',' + typeFilter; } else { const [field, op, value] = typeFilter.split('.'); if (!lastMonthReviewedParams.filter) { lastMonthReviewedParams.filter = {}; } lastMonthReviewedParams.filter[field] = `${op}.${value}`; } } const lastMonthReviewedCount = await handleApiResponse<{ count: number }[]>( postgrestGet('documents', lastMonthReviewedParams), '获取上月已审核文件数量失败', [] ); // 上月已审核文件数量 const lastMonthReviewed = lastMonthReviewedCount[0]?.count || 0; // 计算同比增长 let reviewGrowthValue = 0; let reviewGrowthIsUp = true; if (lastMonthReviewed > 0) { const growthRate = ((monthlyReviewedFiles - lastMonthReviewed) / lastMonthReviewed) * 100; reviewGrowthValue = Math.abs(parseFloat(growthRate.toFixed(1))); reviewGrowthIsUp = growthRate >= 0; } else if (lastMonthReviewed == 0 && monthlyReviewedFiles > 0) { reviewGrowthValue = 100; reviewGrowthIsUp = true; } // 3. 审核通过率 - 本月审核通过率 const thisMonthTotalParams: PostgrestParams = { select: 'count', filter: { audit_status: `eq.1`, created_at: `gte.${startOfThisMonth}`, is_test_document: `eq.false` } }; // 添加类型过滤条件 if (typeFilter) { if (typeFilter.startsWith('(')) { thisMonthTotalParams.or = typeFilter; } else { const [field, op, value] = typeFilter.split('.'); if (!thisMonthTotalParams.filter) { thisMonthTotalParams.filter = {}; } thisMonthTotalParams.filter[field] = `${op}.${value}`; } } const thisMonthTotalCount = await handleApiResponse<{ count: number }[]>( postgrestGet('documents', thisMonthTotalParams), '获取本月审核通过数量失败', [] ); // 本月审核通过数量 const thisMonthPassTotal = thisMonthTotalCount[0]?.count || 0; // 本月审核通过率 const monthlyPassRate = (thisMonthPassTotal > 0 && monthlyReviewedFiles > 0) ? parseFloat(((thisMonthPassTotal / monthlyReviewedFiles) * 100).toFixed(1)) : 0; // 上月审核通过率 const lastMonthTotalParams: PostgrestParams = { select: 'count', filter: { audit_status: `eq.1`, and: `(updated_at.gte.${startOfLastMonth},updated_at.lte.${endOfLastMonth})`, is_test_document: `eq.false` } }; // 添加类型过滤条件 if (typeFilter) { if (typeFilter.startsWith('(')) { lastMonthTotalParams.or = typeFilter; } else { const [field, op, value] = typeFilter.split('.'); if (!lastMonthTotalParams.filter) { lastMonthTotalParams.filter = {}; } lastMonthTotalParams.filter[field] = `${op}.${value}`; } } const lastMonthTotalCount = await handleApiResponse<{ count: number }[]>( postgrestGet('documents', lastMonthTotalParams), '获取上月审核通过数量失败', [] ); // 上月审核通过数量 const lastMonthTotal = lastMonthTotalCount[0]?.count || 0; // 上月审核通过率 const lastMonthPassRate = (lastMonthTotal > 0 && lastMonthReviewed > 0) ? parseFloat(((lastMonthTotal / lastMonthReviewed) * 100).toFixed(1)) : 0; // console.log('上个月-------', lastMonthPassRate); // 计算通过率同比增长 let passRateGrowthValue = 0; let passRateGrowthIsUp = true; if (lastMonthPassRate > 0) { const passRateGrowth = ((monthlyPassRate - lastMonthPassRate) / lastMonthPassRate) * 100; passRateGrowthValue = Math.abs(parseFloat(passRateGrowth.toFixed(1))); passRateGrowthIsUp = passRateGrowth >= 0; } else if (lastMonthPassRate == 0 && monthlyPassRate > 0) { passRateGrowthValue = 100; passRateGrowthIsUp = true; } // console.log('上月通过率-------', lastMonthPassRate); // console.log('本月通过率-------', monthlyPassRate); // 4. 检查出的问题总数(从评估结果表中统计) // 使用新的数据库函数 count_evaluation_results_by_type 获取指定类型文档的问题数量 let thisMonthIssuesCount = 0; let lastMonthIssuesCount = 0; // 根据 reviewType 设置要查询的文档类型 if (reviewType === 'contract') { // 合同类型 - 直接查询类型 1 const typeToQuery = 1; // 调用数据库函数获取本月指定类型的问题数量 const thisMonthIssuesResponse = await handleApiResponse<{ count: number }[]>( postgrestGet(`rpc/count_evaluation_results_by_type?type_val=${typeToQuery}&start_time=${startOfThisMonth}&end_time=${endOfThisMonth}`, { select: '*', filter: {} }), '获取本月问题数据失败', [] ); // 本月问题数量 thisMonthIssuesCount = thisMonthIssuesResponse[0]?.count || 0; // 调用数据库函数获取上月指定类型的问题数量 const lastMonthIssuesResponse = await handleApiResponse<{ count: number }[]>( postgrestGet(`rpc/count_evaluation_results_by_type?type_val=${typeToQuery}&start_time=${startOfLastMonth}&end_time=${endOfLastMonth}`, { select: '*', filter: {} }), '获取上月问题数据失败', [] ); // 上月问题数量 lastMonthIssuesCount = lastMonthIssuesResponse[0]?.count || 0; } else if (reviewType === 'record') { // 记录类型 - 需要查询类型 2 和类型 3,并合并结果 // 查询类型 2 的本月问题数量 const thisMonthType2Response = await handleApiResponse<{ count: number }[]>( postgrestGet(`rpc/count_evaluation_results_by_type?type_val=2&start_time=${startOfThisMonth}&end_time=${endOfThisMonth}`, { select: '*', filter: {} }), '获取本月类型2问题数据失败', [] ); // 查询类型 3 的本月问题数量 const thisMonthType3Response = await handleApiResponse<{ count: number }[]>( postgrestGet(`rpc/count_evaluation_results_by_type?type_val=3&start_time=${startOfThisMonth}&end_time=${endOfThisMonth}`, { select: '*', filter: {} }), '获取本月类型3问题数据失败', [] ); // 合并本月两种类型的问题数量 const thisMonthType2Count = thisMonthType2Response[0]?.count || 0; const thisMonthType3Count = thisMonthType3Response[0]?.count || 0; thisMonthIssuesCount = thisMonthType2Count + thisMonthType3Count; // 查询类型 2 的上月问题数量 const lastMonthType2Response = await handleApiResponse<{ count: number }[]>( postgrestGet(`rpc/count_evaluation_results_by_type?type_val=2&start_time=${startOfLastMonth}&end_time=${endOfLastMonth}`, { select: '*', filter: {} }), '获取上月类型2问题数据失败', [] ); // 查询类型 3 的上月问题数量 const lastMonthType3Response = await handleApiResponse<{ count: number }[]>( postgrestGet(`rpc/count_evaluation_results_by_type?type_val=3&start_time=${startOfLastMonth}&end_time=${endOfLastMonth}`, { select: '*', filter: {} }), '获取上月类型3问题数据失败', [] ); // 合并上月两种类型的问题数量 const lastMonthType2Count = lastMonthType2Response[0]?.count || 0; const lastMonthType3Count = lastMonthType3Response[0]?.count || 0; lastMonthIssuesCount = lastMonthType2Count + lastMonthType3Count; } else { // 如果没有指定类型,则使用原来的查询方式获取所有类型的问题数量 const thisMonthIssuesParams: PostgrestParams = { select: 'count', filter: { and: `(created_at.gte.${startOfThisMonth},created_at.lte.${endOfThisMonth})`, 'evaluated_results->result': 'eq.false' // 使用->操作符访问JSONB字段 } }; // 添加类型过滤条件 if (typeFilter) { if (typeFilter.startsWith('(')) { thisMonthIssuesParams.or = typeFilter; } else { const [field, op, value] = typeFilter.split('.'); if (!thisMonthIssuesParams.filter) { thisMonthIssuesParams.filter = {}; } thisMonthIssuesParams.filter[field] = `${op}.${value}`; } } const thisMonthIssuesResponse = await handleApiResponse<{ count: number }[]>( postgrestGet('evaluation_results', thisMonthIssuesParams), '获取本月问题数据失败', [] ); // 本月问题数量 thisMonthIssuesCount = thisMonthIssuesResponse[0]?.count || 0; // 上月问题数量 const lastMonthIssuesParams: PostgrestParams = { select: 'count', filter: { and: `(created_at.gte.${startOfLastMonth},created_at.lte.${endOfLastMonth})`, 'evaluated_results->result': 'eq.false' // 使用->操作符访问JSONB字段 } }; // 添加类型过滤条件 if (typeFilter) { if (typeFilter.startsWith('(')) { lastMonthIssuesParams.or = typeFilter; } else { const [field, op, value] = typeFilter.split('.'); if (!lastMonthIssuesParams.filter) { lastMonthIssuesParams.filter = {}; } lastMonthIssuesParams.filter[field] = `${op}.${value}`; } } const lastMonthIssuesResponse = await handleApiResponse<{ count: number }[]>( postgrestGet('evaluation_results', lastMonthIssuesParams), '获取上月问题数据失败', [] ); // 上月问题数量 lastMonthIssuesCount = lastMonthIssuesResponse[0]?.count || 0; } // 计算问题数量同比增长 let issuesGrowthValue = 0; let issuesGrowthIsUp = true; if (lastMonthIssuesCount > 0) { const issuesGrowth = ((thisMonthIssuesCount - lastMonthIssuesCount) / lastMonthIssuesCount) * 100; issuesGrowthValue = Math.abs(parseFloat(issuesGrowth.toFixed(1))); issuesGrowthIsUp = issuesGrowth >= 0; }else if(lastMonthIssuesCount == 0 && thisMonthIssuesCount > 0){ issuesGrowthValue = 100; issuesGrowthIsUp = true; } // 返回统计结果 return { todayPendingFiles, monthlyReviewedFiles, monthlyReviewGrowth: { value: reviewGrowthValue, isUp: reviewGrowthIsUp }, monthlyPassRate, passRateGrowth: { value: passRateGrowthValue, isUp: passRateGrowthIsUp }, issuesDetected: thisMonthIssuesCount, issuesGrowth: { value: issuesGrowthValue, isUp: issuesGrowthIsUp } }; } catch (error) { console.error('获取首页数据失败:', error instanceof Error ? error.message : String(error)); // 返回默认值以防止页面崩溃 return { todayPendingFiles: 0, monthlyReviewedFiles: 0, monthlyReviewGrowth: { value: 0, isUp: true }, monthlyPassRate: 0, passRateGrowth: { value: 0, isUp: true }, issuesDetected: 0, issuesGrowth: { value: 0, isUp: true } }; } }