PayrollManagementSystem/frontend/src/api/customers.ts
liuwenxin 32b7940067 feat(customer): 客户评级并入客户管理并落库
- customers 表新增 rating_score/rating_time(V13 迁移 + V10 SQL + init-dev 同步)
- 新端点 PUT /customers/{id}/rating:评分是档案属性,只存总分与评级时间(五项明细不落库)
- 列表排序 order_by=rating_score,未评分客户升序/降序都垫底,id desc 兜底稳定分页
- 前端 RatingCalculatorDialog 并入客户管理(评分列 + 评级计算按钮),删除独立页与路由
- 测试:评级保存/越界/排序垫底 3 例,test_customers.py 18 passed;schema 同步 216 passed
2026-10-23 10:59:33 +08:00

149 lines
5.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 { request } from './request'
import type { PageData } from './types'
/**
* 客户列表项(对应后端 `CustomerOut`)。
*
* owner_personnel_name 由联表带出:归属人员不可考(被物理删除)时为 null,
* owner_personnel_id 仍保留原值供追溯。
*/
export interface CustomerItem {
id: number
company_name: string
/** 客户公司的负责人姓名(非系统内营销人员) */
owner_name: string
contact_person: string | null
contact_phone: string | null
address: string | null
industry: string | null
/** personal 个人户 / manager_personal 经理个人户 / enterprise 企业户(计提规则锚点) */
customer_type: string
owner_personnel_id: number | null
owner_personnel_name: string | null
remark: string | null
/** 评级总分(0-100,评级计算器保存;null=未评分) */
rating_score: number | null
/** 最近评级时间(评级计算器保存评分时刷新;null=从未评级) */
rating_time: string | null
}
export interface CustomerQueryParams {
pageNum?: number
pageSize?: number
/** 公司名称或客户负责人,模糊匹配 */
keyword?: string
customer_type?: string
owner_personnel_id?: number
/** 排序键(后端白名单:id 建档序 / rating_score 评分),默认 id 倒序 */
order_by?: 'id' | 'rating_score'
/** 排序方向,默认 desc */
order?: 'asc' | 'desc'
}
/** 新增客户(owner_personnel_id 为初始归属,可空:先建档后派归属也合法) */
export interface CustomerCreateParams {
company_name: string
owner_name: string
contact_person?: string | null
contact_phone?: string | null
address?: string | null
industry?: string | null
customer_type: string
owner_personnel_id?: number | null
remark?: string | null
}
/**
* 编辑客户:不含归属字段 —— 归属调整统一走 `PUT /{id}/ownership`
* (唯一写归属留痕的入口),编辑表单即使提交归属也会被后端忽略。
*/
export type CustomerUpdateParams = Omit<CustomerCreateParams, 'owner_personnel_id'>
/** 归属变更入参(new_owner_personnel_id 空 = 清空归属) */
export interface CustomerOwnershipParams {
new_owner_personnel_id?: number | null
reason?: string | null
}
/** 保存评级入参:只存总分(五项明细不落库,评分是档案属性而非审计事件) */
export interface CustomerRatingParams {
score: number
}
/** 归属变更留痕条目(对应后端 `OwnershipChangeLogOut`;姓名可随人员消失,ID 固化) */
export interface OwnershipLogItem {
id: number
customer_id: number
old_owner_personnel_id: number | null
new_owner_personnel_id: number | null
old_owner_name: string | null
new_owner_name: string | null
change_reason: string | null
operator_id: number | null
operator_name: string
create_time: string
}
/** 客户分类下拉项(与后端 `core/constants.py` 的值域一致) */
export const CUSTOMER_TYPE_OPTIONS = [
{ label: '个人户', value: 'personal' },
{ label: '经理个人户', value: 'manager_personal' },
{ label: '企业户', value: 'enterprise' },
] as const
/** 分类编码 → 展示名(表格列展示用,未知编码原样回显) */
export function customerTypeLabel(code: string): string {
return CUSTOMER_TYPE_OPTIONS.find((o) => o.value === code)?.label ?? code
}
/** 分页查询客户(keyword 对公司名称/客户负责人模糊匹配,附归属人员姓名) */
export function listCustomers(params: CustomerQueryParams): Promise<PageData<CustomerItem>> {
return request({ url: '/v1/base/customers', method: 'get', params })
}
/** 新增客户(公司名称+负责人组合唯一,冲突由后端拦截) */
export function createCustomer(data: CustomerCreateParams): Promise<CustomerItem> {
return request({ url: '/v1/base/customers', method: 'post', data })
}
/** 编辑客户档案(不含归属;全量提交) */
export function updateCustomer(
customerId: number,
data: CustomerUpdateParams,
): Promise<CustomerItem> {
return request({ url: `/v1/base/customers/${customerId}`, method: 'put', data })
}
/** 删除客户(物理删除) */
export function deleteCustomer(customerId: number): Promise<null> {
return request({ url: `/v1/base/customers/${customerId}`, method: 'delete' })
}
/** 归属变更(唯一写归属留痕的入口;新旧相同后端报「归属未变化」) */
export function changeOwnership(
customerId: number,
data: CustomerOwnershipParams,
): Promise<CustomerItem> {
return request({ url: `/v1/base/customers/${customerId}/ownership`, method: 'put', data })
}
/** 保存评级(评级计算器「保存评分」;只存总分与评级时间,评分只走本端点) */
export function rateCustomer(
customerId: number,
data: CustomerRatingParams,
): Promise<CustomerItem> {
return request({ url: `/v1/base/customers/${customerId}/rating`, method: 'put', data })
}
/** 查某客户的归属变更留痕(分页,按变更时间倒序) */
export function listOwnershipLogs(
customerId: number,
params: { pageNum?: number; pageSize?: number },
): Promise<PageData<OwnershipLogItem>> {
return request({
url: `/v1/base/customers/${customerId}/ownership-logs`,
method: 'get',
params,
})
}