PayrollManagementSystem/frontend/src/api/reports.ts
liuwenxin 04a1a0d307 feat(report): 报表四页与打印视图
- 个人绩效明细/部门绩效汇总/业务统计/回款统计四页,路由组「报表统计」order19-22(allowedRoles admin/finance/leader)
- 明细分页页脚全筛选合计;部门汇总成员内联与跨页下钻;业务统计展开回款/台账;回款统计 8 档区间(档位由后端下发)与桶下钻
- 打印视图独立顶层路由(不挂 BasicLayout):公司页眉走 public 端点、循环翻页取全量(2000 行截断提示)、@media print A4 横版每页表头、签字栏
- AppPagination 只派发 page-change/size-change,四页按事件绑定并补初始加载(@change/v-model 不生效的同类缺陷)
- e2e report_flow.py:四页筛选与导出下载、打印视图 window.print 桩断言

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-19 16:33:37 +08:00

229 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import service, { request } from './request'
import type { PageData } from './types'
/** 报表分页:标准分页四字段 + 全筛选合计(summary 非当前页合计) */
export interface ReportSummary {
row_count: number
performance_total?: string | null
payable_total?: string | null
converted_profit_total?: string | null
ship_total?: string | null
received_total?: string | null
sale_total?: string | null
}
export interface ReportPage<T> extends PageData<T> {
summary: ReportSummary
}
/** 个人绩效明细行(金额/比例一律字符串,前端不做数值运算) */
export interface PersonalDetailRow {
ledger_id: number
business_id: number
business_no: string
personnel_id: number
personnel_name: string
role_code: string
role_name: string
customer_type: string
product_category: string
ship_date: string | null
receipt_date: string
payment_days: number | null
rate_text: string
weight_r: number | null
payment_weight: string | null
performance_amount: string | null
payable_amount: string | null
converted_profit: string | null
is_probation: number
missing_cost: number
calc_version: number
settlement_id: number | null
}
export interface DepartmentMemberRow {
personnel_id: number
personnel_name: string
role_code: string
is_probation: number
performance_sum: string | null
payable_sum: string | null
adjust_extra: string
adjust_deduct: string
adjust_net: string
net_total: string | null
ledger_ids: number[]
}
export interface DepartmentTeamRow {
manager_id: number
manager_name: string
manager_status: number
member_count: number
team_base: string
team_share_amount: string
company_share_amount: string
company_base_ratio: string
adjust_extra: string
adjust_deduct: string
adjust_net: string
net_total: string
frozen_amount: string | null
aggregate_ledger_id: number | null
members: DepartmentMemberRow[]
}
export interface DepartmentSummary {
settlement_month: string
params: {
team_text: string
company_text: string
manager_personal_included: number
params_as_of: string
} | null
teams: DepartmentTeamRow[]
unassigned: DepartmentMemberRow[]
company: {
team_base_total: string
company_base: string
company_share_pct: string
company_share_amount: string
} | null
totals: Record<string, string>
}
export interface BusinessStatsRow {
business_id: number
business_no: string
business_date: string | null
status: number
customer_name: string | null
owner_personnel_name: string | null
total_sale_amount: string | null
total_ship_amount: string | null
total_received_amount: string | null
performance_amount: string | null
payable_amount: string | null
}
export interface BucketRow {
code: string
label: string
min_days: number | null
max_days: number | null
receipt_amount: string | null
receipt_count: number
performance_amount: string | null
payable_amount: string | null
ledger_count: number
}
export interface GroupRow {
code: string
label: string
receipt_amount: string | null
performance_amount: string | null
payable_amount: string | null
ledger_count: number
}
export interface PaymentStats {
settlement_month: string | null
buckets: BucketRow[]
by_customer_type: GroupRow[]
by_product_category: GroupRow[]
totals: Record<string, string | number>
}
export interface PaymentDetailRow {
ledger_id: number
receipt_id: number | null
receipt_batch_no: string | null
amount: string | null
business_id: number
business_no: string
personnel_id: number
personnel_name: string
customer_type: string
product_category: string
ship_date: string | null
receipt_date: string
payment_days: number | null
performance_amount: string | null
payable_amount: string | null
}
/** 报表查询通用筛选(各页按需取用) */
export interface ReportFilterParams {
pageNum?: number
pageSize?: number
settlement_month?: string
personnel_id?: number
customer_type?: string
product_category?: string
role_code?: string
manager_id?: number
keyword?: string
customer_id?: number
owner_personnel_id?: number
status?: number
date_from?: string
date_to?: string
bucket?: string
}
export function listPersonalDetail(
params: ReportFilterParams,
): Promise<ReportPage<PersonalDetailRow>> {
return request({ url: '/v1/reports/personal-detail', method: 'get', params })
}
export function getDepartmentSummary(params: ReportFilterParams): Promise<DepartmentSummary> {
return request({ url: '/v1/reports/department-summary', method: 'get', params })
}
export function listBusinessStats(
params: ReportFilterParams,
): Promise<ReportPage<BusinessStatsRow>> {
return request({ url: '/v1/reports/business-stats', method: 'get', params })
}
export function getPaymentStats(params: ReportFilterParams): Promise<PaymentStats> {
return request({ url: '/v1/reports/payment-stats', method: 'get', params })
}
export function listPaymentDetail(
params: ReportFilterParams,
): Promise<ReportPage<PaymentDetailRow>> {
return request({ url: '/v1/reports/payment-detail', method: 'get', params })
}
export function getPaymentDayBuckets(): Promise<
{ code: string; label: string; min_days: number | null; max_days: number | null }[]
> {
return request({ url: '/v1/reports/payment-day-buckets', method: 'get' })
}
/**
* 导出报表(文件流)。走 axios 实例(带令牌)而非 request 封装:响应是
* xlsx 文件流,不是统一信封,拦截器已对 responseType=blob 直通。
* 服务端文件名是 ASCII(HTTP 头 latin-1 限制),中文名由调用方 link.download 指定。
*/
export async function exportReport(
code: 'personal-detail' | 'department-summary' | 'business-stats' | 'payment-stats',
params: ReportFilterParams,
): Promise<Blob> {
const response = await service.get(`/v1/reports/${code}/export`, {
params,
responseType: 'blob',
})
return response.data as Blob
}
/** 产品类别展示名:报表需额外覆盖「混合业务」(台账行可为 mixed) */
export function reportCategoryLabel(code: string): string {
if (code === 'mixed') return '混合业务'
return { municipal_water: '市政水利', rail_transit: '轨道交通' }[code] ?? code
}