This commit is contained in:
zwgczx committed 2026-03-02 17:52:32 +08:00
1 parent 3950057707
commit a10359f7e0
19 files changed
+349 -299

No files matched your search

+46 -43
View File
@@ -1,6 +1,8 @@
import localforage from 'localforage'
import { expertList, getBasicFeeFromScale, majorList, serviceList, taskList } from '@/sql'
import { addNumbers, roundTo, sumByNumber, toDecimal } from '@/lib/decimal'
import { expertList, majorList, serviceList, taskList } from '@/sql'
import { roundTo, sumByNumber, toDecimal } from '@/lib/decimal'
import { toFiniteNumberOrNull } from '@/lib/number'
import { getBenchmarkBudgetByScale, getScaleBudgetFee } from '@/lib/pricingScaleFee'
interface StoredDetailRowsState<T = any> {
detailRows?: T[]
@@ -58,12 +60,17 @@ export interface PricingMethodTotals {
hourly: number | null
}
const toFiniteNumberOrNull = (value: unknown): number | null =>
typeof value === 'number' && Number.isFinite(value) ? value : null
const hasOwn = (obj: unknown, key: string) =>
Object.prototype.hasOwnProperty.call(obj || {}, key)
const toRowMap = <TRow extends { id: string }>(rows?: TRow[]) => {
const map = new Map<string, TRow>()
for (const row of rows || []) {
map.set(String(row.id), row)
}
return map
}
const getDefaultConsultCategoryFactor = (serviceId: string | number) => {
const service = (serviceList as Record<string, ServiceLite | undefined>)[String(serviceId)]
return toFiniteNumberOrNull(service?.defCoe)
@@ -95,10 +102,7 @@ const mergeScaleRows = (
serviceId: string | number,
rowsFromDb: Array<Partial<ScaleRow> & Pick<ScaleRow, 'id'>> | undefined
): ScaleRow[] => {
const dbValueMap = new Map<string, Partial<ScaleRow> & Pick<ScaleRow, 'id'>>()
for (const row of rowsFromDb || []) {
dbValueMap.set(String(row.id), row)
}
const dbValueMap = toRowMap(rowsFromDb)
const defaultConsultCategoryFactor = getDefaultConsultCategoryFactor(serviceId)
return buildDefaultScaleRows(serviceId).map(row => {
@@ -122,26 +126,26 @@ const mergeScaleRows = (
})
}
const getBenchmarkBudgetByAmount = (amount: MaybeNumber) => {
const result = getBasicFeeFromScale(amount, 'cost')
return result ? roundTo(addNumbers(result.basic, result.optional), 2) : null
}
const getBenchmarkBudgetByAmount = (amount: MaybeNumber) =>
getBenchmarkBudgetByScale(amount, 'cost')
const getBenchmarkBudgetByLandArea = (landArea: MaybeNumber) => {
const result = getBasicFeeFromScale(landArea, 'area')
return result ? roundTo(addNumbers(result.basic, result.optional), 2) : null
}
const getBenchmarkBudgetByLandArea = (landArea: MaybeNumber) =>
getBenchmarkBudgetByScale(landArea, 'area')
const getInvestmentBudgetFee = (row: ScaleRow) => {
const benchmarkBudget = getBenchmarkBudgetByAmount(row.amount)
if (benchmarkBudget == null || row.majorFactor == null || row.consultCategoryFactor == null) return null
return roundTo(toDecimal(benchmarkBudget).mul(row.majorFactor).mul(row.consultCategoryFactor), 2)
return getScaleBudgetFee({
benchmarkBudget: getBenchmarkBudgetByAmount(row.amount),
majorFactor: row.majorFactor,
consultCategoryFactor: row.consultCategoryFactor
})
}
const getLandBudgetFee = (row: ScaleRow) => {
const benchmarkBudget = getBenchmarkBudgetByLandArea(row.landArea)
if (benchmarkBudget == null || row.majorFactor == null || row.consultCategoryFactor == null) return null
return roundTo(toDecimal(benchmarkBudget).mul(row.majorFactor).mul(row.consultCategoryFactor), 2)
return getScaleBudgetFee({
benchmarkBudget: getBenchmarkBudgetByLandArea(row.landArea),
majorFactor: row.majorFactor,
consultCategoryFactor: row.consultCategoryFactor
})
}
const getTaskEntriesByServiceId = (serviceId: string | number) =>
@@ -164,10 +168,7 @@ const mergeWorkloadRows = (
serviceId: string | number,
rowsFromDb: Array<Partial<WorkloadRow> & Pick<WorkloadRow, 'id'>> | undefined
): WorkloadRow[] => {
const dbValueMap = new Map<string, Partial<WorkloadRow> & Pick<WorkloadRow, 'id'>>()
for (const row of rowsFromDb || []) {
dbValueMap.set(String(row.id), row)
}
const dbValueMap = toRowMap(rowsFromDb)
return buildDefaultWorkloadRows(serviceId).map(row => {
const fromDb = dbValueMap.get(row.id)
@@ -216,10 +217,7 @@ const buildDefaultHourlyRows = (): HourlyRow[] =>
const mergeHourlyRows = (
rowsFromDb: Array<Partial<HourlyRow> & Pick<HourlyRow, 'id'>> | undefined
): HourlyRow[] => {
const dbValueMap = new Map<string, Partial<HourlyRow> & Pick<HourlyRow, 'id'>>()
for (const row of rowsFromDb || []) {
dbValueMap.set(String(row.id), row)
}
const dbValueMap = toRowMap(rowsFromDb)
return buildDefaultHourlyRows().map(row => {
const fromDb = dbValueMap.get(row.id)
@@ -239,6 +237,20 @@ const calcHourlyServiceBudget = (row: HourlyRow) => {
return roundTo(toDecimal(row.adoptedBudgetUnitPrice).mul(row.personnelCount).mul(row.workdayCount), 2)
}
const resolveScaleRows = (
serviceId: string,
pricingData: StoredDetailRowsState | null,
htData: StoredDetailRowsState | null
) => {
if (pricingData?.detailRows != null) {
return mergeScaleRows(serviceId, pricingData.detailRows as any)
}
if (htData?.detailRows != null) {
return mergeScaleRows(serviceId, htData.detailRows as any)
}
return buildDefaultScaleRows(serviceId)
}
export const getPricingMethodTotalsForService = async (params: {
contractId: string
serviceId: string | number
@@ -258,20 +270,11 @@ export const getPricingMethodTotalsForService = async (params: {
localforage.getItem<StoredDetailRowsState>(htDbKey)
])
const investRows =
investData?.detailRows != null
? mergeScaleRows(serviceId, investData.detailRows as any)
: htData?.detailRows != null
? mergeScaleRows(serviceId, htData.detailRows as any)
: buildDefaultScaleRows(serviceId)
// 优先使用对应计费页的数据;不存在时回退合同段规模信息,再回退默认字典行。
const investRows = resolveScaleRows(serviceId, investData, htData)
const investScale = sumByNumber(investRows, row => getInvestmentBudgetFee(row))
const landRows =
landData?.detailRows != null
? mergeScaleRows(serviceId, landData.detailRows as any)
: htData?.detailRows != null
? mergeScaleRows(serviceId, htData.detailRows as any)
: buildDefaultScaleRows(serviceId)
const landRows = resolveScaleRows(serviceId, landData, htData)
const landScale = sumByNumber(landRows, row => getLandBudgetFee(row))
const defaultWorkloadRows = buildDefaultWorkloadRows(serviceId)