- 个人绩效明细/部门绩效汇总/业务统计/回款统计四页,路由组「报表统计」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>
229 lines
6.2 KiB
TypeScript
229 lines
6.2 KiB
TypeScript
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
|
||
}
|