import dayjs from 'dayjs'; import { WEB_SERVICE_PREFIX } from '@/constants/service'; import { request } from '../request'; import { type ServiceRequestResult, mapServiceResult, normalizeNullableStringId, normalizeStringId, safeJsonRequestConfig } from './shared'; const TEMPLATE_PREFIX = `${WEB_SERVICE_PREFIX}/project/performance-templates`; const SHEET_PREFIX = `${WEB_SERVICE_PREFIX}/project/performance-sheets`; const TEAM_PREFIX = `${SHEET_PREFIX}/team`; type StringIdResponse = string | number; type TemplateResponse = Omit & { id: StringIdResponse; fileId: StringIdResponse; uploadUserId: StringIdResponse; activeFlag?: boolean | number | string | null; }; type TemplatePageResponse = { total: number | string; list: TemplateResponse[]; }; type SheetResponse = Omit< Api.Performance.Sheet.Sheet, 'id' | 'employeeId' | 'employeeDeptId' | 'managerId' | 'templateId' | 'fileId' > & { id: StringIdResponse; employeeId: StringIdResponse; employeeDeptId: StringIdResponse; managerId: StringIdResponse; templateId: StringIdResponse; fileId?: StringIdResponse | null; }; type SheetPageResponse = { total: number | string; list: SheetResponse[]; }; type StatusLogResponse = Omit & { id: StringIdResponse; sheetId: StringIdResponse; operatorUserId: StringIdResponse; }; type ResponseRecordResponse = Omit< Api.Performance.Sheet.ResponseRecord, 'id' | 'sheetId' | 'statusLogId' | 'responderUserId' > & { id: StringIdResponse; sheetId: StringIdResponse; statusLogId: StringIdResponse; responderUserId: StringIdResponse; }; type MonthlyResultResponse = Omit & { sheetId?: StringIdResponse | null; employeeId: StringIdResponse; }; type TeamSummaryResponse = Omit< Api.Performance.Team.Summary, | 'totalSheetCount' | 'pendingSendCount' | 'pendingConfirmCount' | 'pendingSendUsers' | 'pendingConfirmUsers' | 'deptOrgAverages' > & { totalSheetCount?: number | string | null; pendingSendCount?: number | string | null; pendingConfirmCount?: number | string | null; pendingSendUsers?: Array< Omit & { userId: StringIdResponse; managerUserId: StringIdResponse; sheetId?: StringIdResponse | null; } > | null; pendingConfirmUsers?: Array< Omit & { userId: StringIdResponse; sheetId: StringIdResponse; } > | null; deptOrgAverages?: Array< Omit & { deptId: StringIdResponse; confirmedCount?: number | string | null; } > | null; }; function normalizeBooleanFlag(value: boolean | number | string | null | undefined) { if (typeof value === 'boolean') return value; if (typeof value === 'number') return value === 1; if (typeof value === 'string') { const normalized = value.trim().toLowerCase(); return !['', '0', 'false', 'n', 'no'].includes(normalized); } return false; } function normalizeTotal(value: number | string | null | undefined) { const total = Number(value ?? 0); return Number.isFinite(total) ? Math.max(0, total) : 0; } function normalizeTemplate(response: TemplateResponse): Api.Performance.Template.Template { return { ...response, id: normalizeStringId(response.id), fileId: normalizeStringId(response.fileId), uploadUserId: normalizeStringId(response.uploadUserId), activeFlag: normalizeBooleanFlag(response.activeFlag), remark: response.remark ?? null, scoreCellMapping: response.scoreCellMapping ?? null }; } function normalizeSheet(response: SheetResponse): Api.Performance.Sheet.Sheet { return { ...response, id: normalizeStringId(response.id), employeeId: normalizeStringId(response.employeeId), employeeDeptId: normalizeStringId(response.employeeDeptId), managerId: normalizeStringId(response.managerId), templateId: normalizeStringId(response.templateId), fileId: normalizeNullableStringId(response.fileId), fileName: response.fileName ?? null, statusName: response.statusName || response.statusCode, actualScoreTotal: response.actualScoreTotal ?? null, baseScoreTotal: response.baseScoreTotal ?? null, extraScoreTotal: response.extraScoreTotal ?? null, sentTime: response.sentTime ?? null, confirmedTime: response.confirmedTime ?? null, rejectedTime: response.rejectedTime ?? null, lastStatusReason: response.lastStatusReason ?? null, createTime: response.createTime ?? null, updateTime: response.updateTime ?? null }; } function normalizeStatusLog(response: StatusLogResponse): Api.Performance.Sheet.StatusLog { return { ...response, id: normalizeStringId(response.id), sheetId: normalizeStringId(response.sheetId), operatorUserId: normalizeStringId(response.operatorUserId), reason: response.reason ?? null, remark: response.remark ?? null }; } function normalizeResponseRecord(response: ResponseRecordResponse): Api.Performance.Sheet.ResponseRecord { return { ...response, id: normalizeStringId(response.id), sheetId: normalizeStringId(response.sheetId), statusLogId: normalizeStringId(response.statusLogId), responderUserId: normalizeStringId(response.responderUserId), opinion: response.opinion ?? null }; } function normalizeMonthlyResult(response: MonthlyResultResponse): Api.Performance.Sheet.MonthlyResult { return { ...response, sheetId: normalizeNullableStringId(response.sheetId), employeeId: normalizeStringId(response.employeeId), actualScoreTotal: response.actualScoreTotal ?? null, baseScoreTotal: response.baseScoreTotal ?? null, extraScoreTotal: response.extraScoreTotal ?? null, statusCode: response.statusCode ?? null }; } function normalizeTeamSummary(response: TeamSummaryResponse): Api.Performance.Team.Summary { return { ...response, totalSheetCount: normalizeTotal(response.totalSheetCount), pendingSendCount: normalizeTotal(response.pendingSendCount), pendingConfirmCount: normalizeTotal(response.pendingConfirmCount), pendingSendUsers: (response.pendingSendUsers || []).map(item => ({ ...item, userId: normalizeStringId(item.userId), managerUserId: normalizeStringId(item.managerUserId), sheetId: normalizeNullableStringId(item.sheetId), statusCode: item.statusCode ?? null })), pendingConfirmUsers: (response.pendingConfirmUsers || []).map(item => ({ ...item, userId: normalizeStringId(item.userId), sheetId: normalizeStringId(item.sheetId), sentTime: item.sentTime ?? null })), deptOrgAverages: (response.deptOrgAverages || []).map(item => ({ ...item, deptId: normalizeStringId(item.deptId), averageScore: item.averageScore ?? null, confirmedCount: normalizeTotal(item.confirmedCount) })) }; } function appendValue(query: URLSearchParams, key: string, value: unknown) { if (value === null || value === undefined || value === '') return; if (Array.isArray(value)) { if (!value.length) { query.append(key, ''); return; } value.forEach(item => appendValue(query, key, item)); return; } query.append(key, String(value)); } export function formatToYYYYMM(value?: string | null) { if (!value) return ''; const d = dayjs(value); return d.isValid() ? d.format('YYYY-MM') : value.slice(0, 7); } function createSheetQuery(params: Api.Performance.Sheet.SearchParams = {}) { const query = new URLSearchParams(); query.append('pageNo', String(params.pageNo ?? 1)); query.append('pageSize', String(params.pageSize ?? 10)); appendValue(query, 'employeeIds', params.employeeIds); // 将 periodMonthRange 拆为 periodMonthStart / periodMonthEnd if (params.periodMonthRange?.length === 2) { appendValue(query, 'periodMonthStart', formatToYYYYMM(params.periodMonthRange[0])); appendValue(query, 'periodMonthEnd', formatToYYYYMM(params.periodMonthRange[1])); } // employeeId 单选追加到 employeeIds if (params.employeeId) { query.append('employeeIds', params.employeeId); } appendValue(query, 'employeeDeptId', params.employeeDeptId); appendValue(query, 'managerName', params.managerName); appendValue(query, 'statusCode', params.statusCode); return query.toString(); } function createTemplateQuery(params: Api.Performance.Template.SearchParams = {}) { const query = new URLSearchParams(); query.append('pageNo', String(params.pageNo ?? 1)); query.append('pageSize', String(params.pageSize ?? 10)); appendValue(query, 'templateName', params.templateName); appendValue(query, 'activeFlag', params.activeFlag); return query.toString(); } export async function fetchPerformanceTemplateCurrent() { const result = await request({ ...safeJsonRequestConfig, url: `${TEMPLATE_PREFIX}/current`, method: 'get' }); return mapServiceResult(result as ServiceRequestResult, data => data ? normalizeTemplate(data) : null ); } export async function fetchPerformanceTemplatePage(params: Api.Performance.Template.SearchParams = {}) { const query = createTemplateQuery(params); const result = await request({ ...safeJsonRequestConfig, url: query ? `${TEMPLATE_PREFIX}/page?${query}` : `${TEMPLATE_PREFIX}/page`, method: 'get' }); return mapServiceResult(result as ServiceRequestResult, data => ({ total: normalizeTotal(data.total), list: data.list.map(normalizeTemplate) })); } export async function uploadPerformanceTemplate(data: Api.Performance.Template.UploadParams) { const result = await request({ ...safeJsonRequestConfig, url: `${TEMPLATE_PREFIX}/upload`, method: 'post', data }); return mapServiceResult(result as ServiceRequestResult, normalizeStringId); } export function activatePerformanceTemplate(id: string) { return request({ ...safeJsonRequestConfig, url: `${TEMPLATE_PREFIX}/${id}/activate`, method: 'post' }); } export async function fetchPerformanceSheetPage(params: Api.Performance.Sheet.SearchParams = {}) { const query = createSheetQuery(params); const result = await request({ ...safeJsonRequestConfig, url: query ? `${SHEET_PREFIX}/page?${query}` : `${SHEET_PREFIX}/page`, method: 'get' }); return mapServiceResult(result as ServiceRequestResult, data => ({ total: normalizeTotal(data.total), list: data.list.map(normalizeSheet) })); } export async function fetchPerformanceSheet(id: string) { const result = await request({ ...safeJsonRequestConfig, url: `${SHEET_PREFIX}/${id}`, method: 'get' }); return mapServiceResult(result as ServiceRequestResult, normalizeSheet); } export async function createPerformanceSheet(data: Api.Performance.Sheet.CreateParams) { const result = await request({ ...safeJsonRequestConfig, url: SHEET_PREFIX, method: 'post', data }); return mapServiceResult(result as ServiceRequestResult, normalizeStringId); } export function updatePerformanceSheetExcel(id: string, data: Api.Performance.Sheet.ExcelUpdateParams) { return request({ ...safeJsonRequestConfig, url: `${SHEET_PREFIX}/${id}/excel`, method: 'put', data }); } export function deletePerformanceSheet(id: string) { return request({ ...safeJsonRequestConfig, url: `${SHEET_PREFIX}/${id}`, method: 'delete' }); } export function sendPerformanceSheet(id: string) { return request({ ...safeJsonRequestConfig, url: `${SHEET_PREFIX}/${id}/send`, method: 'post' }); } export function resendPerformanceSheet(id: string) { return request({ ...safeJsonRequestConfig, url: `${SHEET_PREFIX}/${id}/resend`, method: 'post' }); } export function confirmPerformanceSheet(id: string, data: Api.Performance.Sheet.StatusActionParams = {}) { return request({ ...safeJsonRequestConfig, url: `${SHEET_PREFIX}/${id}/confirm`, method: 'post', data }); } export function rejectPerformanceSheet(id: string, data: Api.Performance.Sheet.StatusActionParams) { return request({ ...safeJsonRequestConfig, url: `${SHEET_PREFIX}/${id}/reject`, method: 'post', data }); } export function downloadPerformanceSheet(id: string) { return request({ url: `${SHEET_PREFIX}/${id}/download`, method: 'get', responseType: 'blob' }); } export function batchDownloadPerformanceSheets(data: Api.Performance.Sheet.BatchDownloadParams) { return request({ ...safeJsonRequestConfig, url: `${SHEET_PREFIX}/batch-download`, method: 'post', data, responseType: 'blob' }); } export function exportPerformanceSheets(params: Api.Performance.Sheet.SearchParams = {}) { const query = createSheetQuery(params); return request({ url: query ? `${SHEET_PREFIX}/export?${query}` : `${SHEET_PREFIX}/export`, method: 'get', responseType: 'blob' }); } export async function fetchPerformanceSheetStatusLogs(id: string) { const result = await request({ ...safeJsonRequestConfig, url: `${SHEET_PREFIX}/${id}/status-logs`, method: 'get' }); return mapServiceResult(result as ServiceRequestResult, data => data.map(normalizeStatusLog)); } export async function fetchPerformanceSheetResponseRecords(id: string) { const result = await request({ ...safeJsonRequestConfig, url: `${SHEET_PREFIX}/${id}/response-records`, method: 'get' }); return mapServiceResult(result as ServiceRequestResult, data => data.map(normalizeResponseRecord) ); } export async function fetchPerformanceMonthlyResult(employeeId: string, periodMonth: string) { const result = await request({ ...safeJsonRequestConfig, url: `${SHEET_PREFIX}/monthly-result`, method: 'get', params: { employeeId, periodMonth } }); return mapServiceResult(result as ServiceRequestResult, data => data ? normalizeMonthlyResult(data) : null ); } export function fetchPerformanceSheetStatusDict() { return request({ ...safeJsonRequestConfig, url: `${SHEET_PREFIX}/status-dict`, method: 'get' }); } export function fetchPerformanceSheetStatusTransitions() { return request({ ...safeJsonRequestConfig, url: `${SHEET_PREFIX}/status-transitions`, method: 'get' }); } export async function fetchTeamPerformanceSummary(params: Api.Performance.Team.SummaryParams = {}) { const result = await request({ ...safeJsonRequestConfig, url: `${TEAM_PREFIX}/summary`, method: 'get', params }); return mapServiceResult(result as ServiceRequestResult, normalizeTeamSummary); } export function remindTeamPerformance(data: Api.Performance.Team.RemindParams) { return request({ ...safeJsonRequestConfig, url: `${TEAM_PREFIX}/remind`, method: 'post', data }); }