- 业务页:明细行编辑器、详情抽屉五分区(含状态时间线与毛利润卡片) - 回款页:业务→发货批次级联指定(可清空)、已核算行禁改禁删 - 金额/比率字符串直出;毛利润卡片注明不含运费口径 Co-Authored-By: Claude Code <noreply@anthropic.com>
295 lines
9.2 KiB
TypeScript
295 lines
9.2 KiB
TypeScript
import { request } from './request'
|
||
import type { PageData } from './types'
|
||
|
||
/**
|
||
* 业务产品明细行(对应后端 `BusinessItemOut`)。
|
||
*
|
||
* 数量与金额一律字符串直出 —— 金额红线:不经 float、不 toFixed,
|
||
* Decimal 运算收敛在后端 service 层。
|
||
*/
|
||
export interface BusinessItemRow {
|
||
id: number
|
||
product_id: number | null
|
||
product_name: string
|
||
spec_model: string | null
|
||
unit: string | null
|
||
/** municipal_water 市政水利 / rail_transit 轨道交通 —— 行级折算锚点 */
|
||
product_category: string
|
||
/** 数字字符串,>0 */
|
||
quantity: string
|
||
sale_price: string | null
|
||
/** 行销售额 = 数量 × 销售单价,后端计算固化 */
|
||
sale_amount: string
|
||
cost_amount: string | null
|
||
guided_price: string | null
|
||
remark: string | null
|
||
}
|
||
|
||
/** 业务列表项(对应后端 `BusinessOut`;四个汇总金额均为字符串直出) */
|
||
export interface BusinessItem {
|
||
id: number
|
||
business_no: string
|
||
customer_id: number
|
||
customer_name: string | null
|
||
/** ISO 串(YYYY-MM-DD) */
|
||
business_date: string | null
|
||
/** 1执行中 2已完成 3已终止 */
|
||
status: number
|
||
owner_personnel_id: number | null
|
||
owner_personnel_name: string | null
|
||
assistant_personnel_id: number | null
|
||
assistant_personnel_name: string | null
|
||
/** 特殊业务标记:1是 0否 */
|
||
is_special: number
|
||
special_note: string | null
|
||
total_sale_amount: string | null
|
||
total_cost_amount: string | null
|
||
total_ship_amount: string | null
|
||
total_received_amount: string | null
|
||
total_freight_amount: string | null
|
||
remark: string | null
|
||
}
|
||
|
||
/** 业务详情:附产品明细行(编辑弹窗一次回显) */
|
||
export interface BusinessDetail extends BusinessItem {
|
||
items: BusinessItemRow[]
|
||
}
|
||
|
||
export interface BusinessQueryParams {
|
||
pageNum?: number
|
||
pageSize?: number
|
||
/** 业务编号/公司名称,模糊匹配 */
|
||
keyword?: string
|
||
status?: number
|
||
customer_id?: number
|
||
owner_personnel_id?: number
|
||
/** 业务日期起(含),ISO 串 */
|
||
date_from?: string
|
||
/** 业务日期止(含),ISO 串 */
|
||
date_to?: string
|
||
}
|
||
|
||
/** 明细行入参(product_id 空 = 自由录入;金额/数量为数字字符串) */
|
||
export interface BusinessItemParams {
|
||
product_id?: number | null
|
||
product_name: string
|
||
spec_model?: string | null
|
||
unit?: string | null
|
||
product_category: string
|
||
quantity: string
|
||
sale_price?: string | null
|
||
cost_amount?: string | null
|
||
guided_price?: string | null
|
||
remark?: string | null
|
||
}
|
||
|
||
/**
|
||
* 创建业务:主表信息 + 明细行(≥1)。
|
||
*
|
||
* is_special=1 时 special_note 必填(后端校验,前端同步拦截)。
|
||
*/
|
||
export interface BusinessCreateParams {
|
||
customer_id: number
|
||
business_date?: string | null
|
||
owner_personnel_id?: number | null
|
||
assistant_personnel_id?: number | null
|
||
is_special?: number
|
||
special_note?: string | null
|
||
items: BusinessItemParams[]
|
||
remark?: string | null
|
||
}
|
||
|
||
/**
|
||
* 编辑业务:明细全量替换并重算汇总。
|
||
*
|
||
* 不含归属字段 —— 归属调整统一走 `PUT /{id}/ownership`(唯一写归属
|
||
* 留痕的入口),编辑表单即使提交归属也会被后端忽略。
|
||
*/
|
||
export interface BusinessUpdateParams {
|
||
customer_id: number
|
||
business_date?: string | null
|
||
is_special?: number
|
||
special_note?: string | null
|
||
items: BusinessItemParams[]
|
||
remark?: string | null
|
||
}
|
||
|
||
/** 状态流转入参:执行中 → 2已完成 / 3已终止;终止时 reason 必填 */
|
||
export interface BusinessStatusParams {
|
||
status: number
|
||
reason?: string | null
|
||
}
|
||
|
||
/** 归属变更入参(新负责/新协助;前后值写入留痕,不回溯历史) */
|
||
export interface BusinessOwnershipParams {
|
||
new_owner_personnel_id?: number | null
|
||
new_assistant_personnel_id?: number | null
|
||
reason?: string | null
|
||
}
|
||
|
||
/** 业务归属变更留痕条目(对应后端 `OwnershipChangeLogOut`;姓名可随人员消失,ID 固化) */
|
||
export interface OwnershipLogItem {
|
||
id: number
|
||
business_id: number
|
||
old_owner_personnel_id: number | null
|
||
new_owner_personnel_id: number | null
|
||
old_assistant_personnel_id: number | null
|
||
new_assistant_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
|
||
}
|
||
|
||
/** 业务状态流转记录(对应后端 `BusinessStatusLogOut`;创建首条 old=new=1) */
|
||
export interface StatusLogItem {
|
||
id: number
|
||
business_id: number
|
||
old_status: number
|
||
new_status: number
|
||
change_reason: string | null
|
||
operator_id: number | null
|
||
operator_name: string
|
||
create_time: string
|
||
}
|
||
|
||
/** 毛利润视图行(对应后端 `GrossProfitRowOut`);成本缺失行派生列为 null */
|
||
export interface GrossProfitRowItem {
|
||
item_id: number
|
||
product_category: string
|
||
product_name: string
|
||
spec_model: string | null
|
||
quantity: string
|
||
sale_amount: string
|
||
cost_amount: string | null
|
||
profit_amount: string | null
|
||
profit_rate: string | null
|
||
threshold: string
|
||
converted_profit: string | null
|
||
missing_reason: string | null
|
||
}
|
||
|
||
/** 按产品类别的毛利润汇总(成本缺失行不计入聚合) */
|
||
export interface GrossProfitCategory {
|
||
product_category: string
|
||
sale_amount: string
|
||
cost_amount: string
|
||
profit_amount: string
|
||
/** 分数字符串原样(如 "997/1000"),不做数值化展示 */
|
||
profit_rate: string
|
||
threshold: string
|
||
converted_profit: string
|
||
}
|
||
|
||
/** 毛利润数据视图(对应后端 `GrossProfitOut`) */
|
||
export interface GrossProfitView {
|
||
business_id: number
|
||
/** 参数取值时点(默认今日),ISO 串 */
|
||
as_of: string
|
||
rows: GrossProfitRowItem[]
|
||
categories: GrossProfitCategory[]
|
||
missing_count: number
|
||
note: string
|
||
}
|
||
|
||
/** 业务状态下拉项(与后端值域一致;执行中=1 已完成=2 已终止=3) */
|
||
export const BUSINESS_STATUS_OPTIONS = [
|
||
{ label: '执行中', value: 1 },
|
||
{ label: '已完成', value: 2 },
|
||
{ label: '已终止', value: 3 },
|
||
] as const
|
||
|
||
/** 状态编码 → 展示名 */
|
||
export function businessStatusLabel(status: number): string {
|
||
return BUSINESS_STATUS_OPTIONS.find((o) => o.value === status)?.label ?? `状态${status}`
|
||
}
|
||
|
||
/** 状态编码 → 标签类型(三色:执行中 primary / 已完成 success / 已终止 danger) */
|
||
export function businessStatusTagType(status: number): 'primary' | 'success' | 'danger' | 'info' {
|
||
if (status === 2) return 'success'
|
||
if (status === 3) return 'danger'
|
||
return 'primary'
|
||
}
|
||
|
||
/** 分页查询业务(编号/公司名称模糊,可按状态/客户/归属/日期范围筛选) */
|
||
export function listBusinesses(params: BusinessQueryParams): Promise<PageData<BusinessItem>> {
|
||
return request({ url: '/v1/business/businesses', method: 'get', params })
|
||
}
|
||
|
||
/** 创建业务(编号自动生成,写首条状态留痕) */
|
||
export function createBusiness(data: BusinessCreateParams): Promise<BusinessItem> {
|
||
return request({ url: '/v1/business/businesses', method: 'post', data })
|
||
}
|
||
|
||
/** 业务详情(附产品明细行) */
|
||
export function getBusinessDetail(businessId: number): Promise<BusinessDetail> {
|
||
return request({ url: `/v1/business/businesses/${businessId}`, method: 'get' })
|
||
}
|
||
|
||
/** 编辑业务(明细全量替换;归属不在此端点调整) */
|
||
export function updateBusiness(
|
||
businessId: number,
|
||
data: BusinessUpdateParams,
|
||
): Promise<BusinessItem> {
|
||
return request({ url: `/v1/business/businesses/${businessId}`, method: 'put', data })
|
||
}
|
||
|
||
/** 删除业务(有发货或回款记录时后端拒绝,应改为已终止) */
|
||
export function deleteBusiness(businessId: number): Promise<null> {
|
||
return request({ url: `/v1/business/businesses/${businessId}`, method: 'delete' })
|
||
}
|
||
|
||
/** 状态流转(终态不可再变更;终止必填原因) */
|
||
export function changeBusinessStatus(
|
||
businessId: number,
|
||
data: BusinessStatusParams,
|
||
): Promise<BusinessItem> {
|
||
return request({ url: `/v1/business/businesses/${businessId}/status`, method: 'put', data })
|
||
}
|
||
|
||
/** 调整负责/协助营销人员(同事务写归属变更留痕) */
|
||
export function changeBusinessOwnership(
|
||
businessId: number,
|
||
data: BusinessOwnershipParams,
|
||
): Promise<BusinessItem> {
|
||
return request({ url: `/v1/business/businesses/${businessId}/ownership`, method: 'put', data })
|
||
}
|
||
|
||
/** 某业务的归属变更留痕(分页,按变更时间倒序) */
|
||
export function listOwnershipLogs(
|
||
businessId: number,
|
||
params: { pageNum?: number; pageSize?: number },
|
||
): Promise<PageData<OwnershipLogItem>> {
|
||
return request({
|
||
url: `/v1/business/businesses/${businessId}/ownership-logs`,
|
||
method: 'get',
|
||
params,
|
||
})
|
||
}
|
||
|
||
/** 某业务的状态流转时间线(分页,按时间正序,从创建起展示) */
|
||
export function listStatusLogs(
|
||
businessId: number,
|
||
params: { pageNum?: number; pageSize?: number },
|
||
): Promise<PageData<StatusLogItem>> {
|
||
return request({
|
||
url: `/v1/business/businesses/${businessId}/status-logs`,
|
||
method: 'get',
|
||
params,
|
||
})
|
||
}
|
||
|
||
/** 毛利润数据视图(as_of 缺省=今日;阈值按该时点参数快照) */
|
||
export function getGrossProfit(
|
||
businessId: number,
|
||
asOf?: string,
|
||
): Promise<GrossProfitView> {
|
||
return request({
|
||
url: `/v1/business/businesses/${businessId}/gross-profit`,
|
||
method: 'get',
|
||
params: asOf ? { as_of: asOf } : undefined,
|
||
})
|
||
}
|