This commit is contained in:
zwgczx committed 2026-03-07 15:32:54 +08:00
1 parent ad4e9cdee0
commit 043e1fc879
8 files changed
+529 -112

No files matched your search

+74 -9
View File
@@ -53,10 +53,13 @@ interface HourlyRow {
interface MajorLite {
code: string
defCoe: number | null
hasCost?: boolean
hasArea?: boolean
}
interface ServiceLite {
defCoe: number | null
onlyCostScale?: boolean | null
}
interface TaskLite {
@@ -77,6 +80,12 @@ export interface PricingMethodTotals {
hourly: number | null
}
interface PricingMethodTotalsOptions {
excludeInvestmentCostAndAreaRows?: boolean
}
const ONLY_COST_SCALE_ROW_ID = '__only-cost-scale-total__'
const hasOwn = (obj: unknown, key: string) =>
Object.prototype.hasOwnProperty.call(obj || {}, key)
@@ -93,6 +102,11 @@ const getDefaultConsultCategoryFactor = (serviceId: string | number) => {
return toFiniteNumberOrNull(service?.defCoe)
}
const isOnlyCostScaleService = (serviceId: string | number) => {
const service = (getServiceDictById() as Record<string, ServiceLite | undefined>)[String(serviceId)]
return service?.onlyCostScale === true
}
const majorById = new Map(getMajorDictEntries().map(({ id, item }) => [id, item as MajorLite]))
const majorIdAliasMap = getMajorIdAliasMap()
@@ -102,6 +116,15 @@ const getDefaultMajorFactorById = (id: string) => {
return toFiniteNumberOrNull(major?.defCoe)
}
const isDualScaleMajorById = (id: string) => {
const resolvedId = majorById.has(id) ? id : majorIdAliasMap.get(id) || id
const major = majorById.get(resolvedId)
if (!major) return false
const hasCost = major.hasCost !== false
const hasArea = major.hasArea !== false
return hasCost && hasArea
}
const resolveFactorValue = (
row: { budgetValue?: number | null; standardFactor?: number | null } | undefined,
fallback: number | null
@@ -227,6 +250,31 @@ const getInvestmentBudgetFee = (row: ScaleRow) => {
})
}
const getOnlyCostScaleBudgetFee = (
serviceId: string,
rowsFromDb: Array<Record<string, unknown>> | undefined,
consultCategoryFactorMap?: Map<string, number | null>
) => {
const totalAmount = sumByNumber(rowsFromDb || [], row =>
typeof row?.amount === 'number' && Number.isFinite(row.amount) ? row.amount : null
)
const onlyRow = (rowsFromDb || []).find(row => String(row?.id || '') === ONLY_COST_SCALE_ROW_ID)
const consultCategoryFactor =
toFiniteNumberOrNull(onlyRow?.consultCategoryFactor) ??
consultCategoryFactorMap?.get(String(serviceId)) ??
getDefaultConsultCategoryFactor(serviceId)
const majorFactor = toFiniteNumberOrNull(onlyRow?.majorFactor) ?? 1
const workStageFactor = toFiniteNumberOrNull(onlyRow?.workStageFactor) ?? 1
const workRatio = toFiniteNumberOrNull(onlyRow?.workRatio) ?? 100
return getScaleBudgetFee({
benchmarkBudget: getBenchmarkBudgetByAmount(totalAmount),
majorFactor,
consultCategoryFactor,
workStageFactor,
workRatio
})
}
const getLandBudgetFee = (row: ScaleRow) => {
return getScaleBudgetFee({
benchmarkBudget: getBenchmarkBudgetByLandArea(row.landArea),
@@ -373,6 +421,7 @@ const resolveScaleRows = (
export const getPricingMethodTotalsForService = async (params: {
contractId: string
serviceId: string | number
options?: PricingMethodTotalsOptions
}): Promise<PricingMethodTotals> => {
const serviceId = String(params.serviceId)
const htDbKey = `ht-info-v3-${params.contractId}`
@@ -395,16 +444,30 @@ export const getPricingMethodTotalsForService = async (params: {
const consultCategoryFactorMap = buildConsultCategoryFactorMap(consultFactorData)
const majorFactorMap = buildMajorFactorMap(majorFactorData)
const onlyCostScale = isOnlyCostScaleService(serviceId)
// 优先使用对应计费页的数据;不存在时回退合同段规模信息,再回退默认字典行。
const investRows = resolveScaleRows(
serviceId,
investData,
htData,
consultCategoryFactorMap,
majorFactorMap
)
const investScale = sumByNumber(investRows, row => getInvestmentBudgetFee(row))
const excludeInvestmentCostAndAreaRows = params.options?.excludeInvestmentCostAndAreaRows === true
const investScale = onlyCostScale
? getOnlyCostScaleBudgetFee(
serviceId,
(investData?.detailRows as Array<Record<string, unknown>> | undefined) ||
(htData?.detailRows as Array<Record<string, unknown>> | undefined),
consultCategoryFactorMap
)
: (() => {
const investRows = resolveScaleRows(
serviceId,
investData,
htData,
consultCategoryFactorMap,
majorFactorMap
)
return sumByNumber(investRows, row => {
if (excludeInvestmentCostAndAreaRows && isDualScaleMajorById(row.id)) return null
return getInvestmentBudgetFee(row)
})
})()
const landRows = resolveScaleRows(
serviceId,
@@ -443,13 +506,15 @@ export const getPricingMethodTotalsForService = async (params: {
export const getPricingMethodTotalsForServices = async (params: {
contractId: string
serviceIds: Array<string | number>
options?: PricingMethodTotalsOptions
}) => {
const result = new Map<string, PricingMethodTotals>()
await Promise.all(
params.serviceIds.map(async serviceId => {
const totals = await getPricingMethodTotalsForService({
contractId: params.contractId,
serviceId
serviceId,
options: params.options
})
result.set(String(serviceId), totals)
})