修复数据导出不正确
This commit is contained in:
parent
99684c04f2
commit
aed6fe2bfa
@ -863,6 +863,10 @@ const getSelectedServiceIdsWithoutFixed = () =>
|
||||
const ensurePricingDetailRowsForCurrentSelection = async () => {
|
||||
const serviceIds = getSelectedServiceIdsWithoutFixed()
|
||||
if (serviceIds.length === 0) return
|
||||
console.log('[zxfw][ensure-current-selection] ' + JSON.stringify({
|
||||
contractId: props.contractId,
|
||||
serviceIds
|
||||
}))
|
||||
await ensurePricingMethodDetailRowsForServices({
|
||||
contractId: props.contractId,
|
||||
serviceIds,
|
||||
@ -875,7 +879,6 @@ const ensurePricingDetailRowsForCurrentSelection = async () => {
|
||||
* 计价法变更场景统一走这里,最终会触发 applyFixedRowTotals。
|
||||
*/
|
||||
const fillPricingTotalsForServiceIds = async (serviceIds: string[]) => {
|
||||
|
||||
const currentState = getCurrentContractState()
|
||||
const targetIds = Array.from(
|
||||
new Set(
|
||||
@ -893,6 +896,21 @@ const fillPricingTotalsForServiceIds = async (serviceIds: string[]) => {
|
||||
return
|
||||
}
|
||||
|
||||
console.log('[zxfw][fill-pricing-totals][start] ' + JSON.stringify({
|
||||
contractId: props.contractId,
|
||||
requestedIds: serviceIds,
|
||||
targetIds,
|
||||
currentRows: currentState.detailRows.map(row => ({
|
||||
id: row.id,
|
||||
investScale: row.investScale,
|
||||
landScale: row.landScale,
|
||||
workload: row.workload,
|
||||
hourly: row.hourly,
|
||||
subtotal: row.subtotal,
|
||||
finalFee: row.finalFee
|
||||
}))
|
||||
}))
|
||||
|
||||
await ensurePricingMethodDetailRowsForServices({
|
||||
contractId: props.contractId,
|
||||
serviceIds: targetIds,
|
||||
@ -905,6 +923,15 @@ const fillPricingTotalsForServiceIds = async (serviceIds: string[]) => {
|
||||
options: PRICING_TOTALS_OPTIONS
|
||||
})
|
||||
|
||||
console.log('[zxfw][fill-pricing-totals][totals] ' + JSON.stringify({
|
||||
contractId: props.contractId,
|
||||
targetIds,
|
||||
totals: targetIds.map(id => ({
|
||||
serviceId: id,
|
||||
totals: totalsByServiceId.get(String(id)) || null
|
||||
}))
|
||||
}))
|
||||
|
||||
const targetSet = new Set(targetIds.map(id => String(id)))
|
||||
const nextRows = currentState.detailRows.map(row => {
|
||||
if (isFixedRow(row) || !targetSet.has(String(row.id))) return row
|
||||
@ -1014,15 +1041,23 @@ const applySelection = async (codes: string[]) => {
|
||||
* 服务勾选变化入口:先更新行,再刷新新增服务的计价汇总。
|
||||
*/
|
||||
const handleServiceSelectionChange = async (ids: string[]) => {
|
||||
|
||||
const prevIds = [...selectedIds.value]
|
||||
console.log('[zxfw][selection-change][start] ' + JSON.stringify({
|
||||
contractId: props.contractId,
|
||||
prevIds,
|
||||
nextIds: ids
|
||||
}))
|
||||
await applySelection(ids)
|
||||
const nextSelectedIds = getCurrentContractState().selectedIds || []
|
||||
const nextSelectedSet = new Set(nextSelectedIds)
|
||||
const addedIds = nextSelectedIds.filter(id => !prevIds.includes(id) && nextSelectedSet.has(id))
|
||||
console.log('[zxfw][selection-change][after-apply] ' + JSON.stringify({
|
||||
contractId: props.contractId,
|
||||
nextSelectedIds,
|
||||
addedIds
|
||||
}))
|
||||
await ensureWorkContentStateForServices(addedIds)
|
||||
await fillPricingTotalsForServiceIds(addedIds)
|
||||
await ensurePricingDetailRowsForCurrentSelection()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -138,6 +138,16 @@ const hasMeaningfulFactorValue = (rows: SourceRow[] | undefined) =>
|
||||
return hasBudgetValue || hasRemark
|
||||
})
|
||||
|
||||
const hasUsablePersistedRows = (state: GridState | null | undefined) =>
|
||||
Array.isArray(state?.detailRows) &&
|
||||
state.detailRows.some(row => {
|
||||
const hasFactor =
|
||||
typeof row?.budgetValue === 'number' ||
|
||||
typeof row?.standardFactor === 'number'
|
||||
const hasRemark = typeof row?.remark === 'string' && row.remark.trim() !== ''
|
||||
return hasFactor || hasRemark || String(row?.id || '').trim() !== ''
|
||||
})
|
||||
|
||||
const mergeWithDictRows = (rowsFromDb: SourceRow[] | undefined): FactorRow[] => {
|
||||
const dbValueMap = new Map<string, SourceRow>()
|
||||
for (const row of rowsFromDb || []) {
|
||||
@ -308,7 +318,7 @@ const saveFactorChangeState = async (changedRowIds: string[]) => {
|
||||
const loadGridState = async (storageKey: string): Promise<GridState | null> => {
|
||||
if (!storageKey) return null
|
||||
const piniaData = await zxFwPricingStore.loadKeyState<GridState>(storageKey)
|
||||
if (piniaData?.detailRows && Array.isArray(piniaData.detailRows)) return piniaData
|
||||
if (hasUsablePersistedRows(piniaData)) return piniaData
|
||||
|
||||
// 兼容历史 kvStore 数据:命中后迁移到 pinia keyed state。
|
||||
const legacyData = await kvStore.getItem<GridState>(storageKey)
|
||||
|
||||
@ -987,15 +987,31 @@ const getPiniaPersistStores = () =>
|
||||
}
|
||||
})
|
||||
|
||||
const hasExportableFactorRows = (rows: FactorRowLike[] | undefined) =>
|
||||
Array.isArray(rows) &&
|
||||
rows.some(row => {
|
||||
const rowId = toSafeInteger(row?.id)
|
||||
const coe = toFiniteNumber(row?.budgetValue) ?? toFiniteNumber(row?.standardFactor)
|
||||
const remark = typeof row?.remark === 'string' ? row.remark.trim() : ''
|
||||
return rowId != null || coe != null || remark !== ''
|
||||
})
|
||||
|
||||
const loadFactorRowsState = async (storageKey: string) => {
|
||||
const [piniaData, kvData] = await Promise.all([
|
||||
zxFwPricingStore.loadKeyState<DetailRowsStorageLike<FactorRowLike>>(storageKey),
|
||||
kvStore.getItem<DetailRowsStorageLike<FactorRowLike>>(storageKey)
|
||||
])
|
||||
const piniaRows = Array.isArray(piniaData?.detailRows) ? piniaData.detailRows : undefined
|
||||
const kvRows = Array.isArray(kvData?.detailRows) ? kvData.detailRows : undefined
|
||||
const resolved = hasExportableFactorRows(piniaRows)
|
||||
? piniaData
|
||||
: hasExportableFactorRows(kvRows)
|
||||
? kvData
|
||||
: (piniaData ?? kvData ?? null)
|
||||
return {
|
||||
piniaData,
|
||||
kvData,
|
||||
resolved: piniaData || kvData || null
|
||||
resolved
|
||||
}
|
||||
}
|
||||
|
||||
@ -1197,6 +1213,7 @@ const buildExportReportPayload = async (): Promise<ExportReportPayload> => {
|
||||
|
||||
const projectServiceCoes = buildProjectServiceCoes(resolveExportFactorRows(consultCategoryFactorState))
|
||||
const projectMajorCoes = buildProjectMajorCoes(resolveExportFactorRows(majorFactorState))
|
||||
|
||||
const projectName = isNonEmptyString(projectInfo.projectName)
|
||||
? projectInfo.projectName.trim()
|
||||
: t('tab.messages.defaultProjectName')
|
||||
@ -1352,10 +1369,22 @@ const buildExportReportPayload = async (): Promise<ExportReportPayload> => {
|
||||
})
|
||||
}
|
||||
|
||||
console.log('[export][service-methods]', {
|
||||
console.log('[export][service-methods] ' + JSON.stringify({
|
||||
contractId,
|
||||
serviceId: serviceIdText,
|
||||
methodAvailability,
|
||||
rawLengths: {
|
||||
method1: Array.isArray(method1Raw?.detailRows) ? method1Raw.detailRows.length : -1,
|
||||
method2: Array.isArray(method2Raw?.detailRows) ? method2Raw.detailRows.length : -1,
|
||||
method3: Array.isArray(method3Raw?.detailRows) ? method3Raw.detailRows.length : -1,
|
||||
method4: Array.isArray(method4Raw?.detailRows) ? method4Raw.detailRows.length : -1
|
||||
},
|
||||
rawSamples: {
|
||||
method1: Array.isArray(method1Raw?.detailRows) ? method1Raw.detailRows[0] : null,
|
||||
method2: Array.isArray(method2Raw?.detailRows) ? method2Raw.detailRows[0] : null,
|
||||
method3: Array.isArray(method3Raw?.detailRows) ? method3Raw.detailRows[0] : null,
|
||||
method4: Array.isArray(method4Raw?.detailRows) ? method4Raw.detailRows[0] : null
|
||||
},
|
||||
exported: {
|
||||
method1: Boolean(method1),
|
||||
method2: Boolean(method2),
|
||||
@ -1364,7 +1393,7 @@ const buildExportReportPayload = async (): Promise<ExportReportPayload> => {
|
||||
},
|
||||
fee,
|
||||
finalFee
|
||||
})
|
||||
}))
|
||||
|
||||
const service: ExportService = {
|
||||
id: serviceId,
|
||||
@ -2343,3 +2372,4 @@ watch(
|
||||
</template>
|
||||
|
||||
<style scoped src="@/features/tab/tab.css"></style>
|
||||
|
||||
|
||||
@ -50,6 +50,8 @@ const getOnlyCostScaleSummaryAmount = (
|
||||
|
||||
interface ScaleRow {
|
||||
id: string
|
||||
hasCost?: boolean
|
||||
hasArea?: boolean
|
||||
amount: number | null
|
||||
landArea: number | null
|
||||
benchmarkBudgetBasicChecked: boolean
|
||||
@ -327,6 +329,8 @@ const buildDefaultScaleRows = (
|
||||
consultCategoryFactorMap?.get(String(serviceId)) ?? getDefaultConsultCategoryFactor(serviceId)
|
||||
return getMajorLeafIds().map(id => ({
|
||||
id,
|
||||
hasCost: isCostMajorById(id),
|
||||
hasArea: isAreaMajorById(id),
|
||||
amount: null,
|
||||
landArea: null,
|
||||
benchmarkBudgetBasicChecked: true,
|
||||
@ -367,6 +371,14 @@ const mergeScaleRows = (
|
||||
|
||||
return {
|
||||
...row,
|
||||
hasCost:
|
||||
typeof (fromDb as { hasCost?: unknown }).hasCost === 'boolean'
|
||||
? Boolean((fromDb as { hasCost?: unknown }).hasCost)
|
||||
: row.hasCost,
|
||||
hasArea:
|
||||
typeof (fromDb as { hasArea?: unknown }).hasArea === 'boolean'
|
||||
? Boolean((fromDb as { hasArea?: unknown }).hasArea)
|
||||
: row.hasArea,
|
||||
amount: toFiniteNumberOrNull(fromDb.amount),
|
||||
landArea: toFiniteNumberOrNull(fromDb.landArea),
|
||||
benchmarkBudgetBasicChecked:
|
||||
@ -490,6 +502,8 @@ const buildInvestScaleSingleTotalDetailRows = (
|
||||
return [
|
||||
{
|
||||
id: onlyCostRowId,
|
||||
hasCost: true,
|
||||
hasArea: false,
|
||||
amount: resolvedTotalAmount,
|
||||
landArea: null,
|
||||
consultCategoryFactor,
|
||||
@ -657,6 +671,8 @@ const normalizeScopedScaleRows = (
|
||||
const hasWorkRatio = hasOwn(row, 'workRatio')
|
||||
return {
|
||||
id: resolvedMajorId,
|
||||
hasCost: isCostMajorById(resolvedMajorId),
|
||||
hasArea: isAreaMajorById(resolvedMajorId),
|
||||
amount: toFiniteNumberOrNull(row.amount),
|
||||
landArea: toFiniteNumberOrNull(row.landArea),
|
||||
benchmarkBudgetBasicChecked:
|
||||
@ -944,16 +960,49 @@ export const ensurePricingMethodDetailRowsForServices = async (params: {
|
||||
const workloadData = toStoredDetailRowsState(storeWorkloadData) || workloadDataFallback
|
||||
const hourlyData = toStoredDetailRowsState(storeHourlyData) || hourlyDataFallback
|
||||
|
||||
const shouldInitInvest = !Array.isArray(investData?.detailRows) || investData!.detailRows!.length === 0
|
||||
const shouldInitLand = !Array.isArray(landData?.detailRows) || landData!.detailRows!.length === 0
|
||||
const shouldInitWorkload = !Array.isArray(workloadData?.detailRows) || workloadData!.detailRows!.length === 0
|
||||
const shouldInitHourly = !Array.isArray(hourlyData?.detailRows) || hourlyData!.detailRows!.length === 0
|
||||
const shouldInitInvest = !Array.isArray(investData?.detailRows)
|
||||
const shouldInitLand = !Array.isArray(landData?.detailRows)
|
||||
const shouldInitWorkload = !Array.isArray(workloadData?.detailRows)
|
||||
const shouldInitHourly = !Array.isArray(hourlyData?.detailRows)
|
||||
|
||||
console.log('[pricing][ensure-detail-rows][before] ' + JSON.stringify({
|
||||
contractId: params.contractId,
|
||||
serviceId,
|
||||
shouldInit: {
|
||||
invest: shouldInitInvest,
|
||||
land: shouldInitLand,
|
||||
workload: shouldInitWorkload,
|
||||
hourly: shouldInitHourly
|
||||
},
|
||||
existingLengths: {
|
||||
invest: Array.isArray(investData?.detailRows) ? investData.detailRows.length : -1,
|
||||
land: Array.isArray(landData?.detailRows) ? landData.detailRows.length : -1,
|
||||
workload: Array.isArray(workloadData?.detailRows) ? workloadData.detailRows.length : -1,
|
||||
hourly: Array.isArray(hourlyData?.detailRows) ? hourlyData.detailRows.length : -1
|
||||
}
|
||||
}))
|
||||
|
||||
const writeTasks: Promise<unknown>[] = []
|
||||
let defaultRows: PricingMethodDefaultDetailRows | null = null
|
||||
const getDefaultRows = () => {
|
||||
if (!defaultRows) {
|
||||
defaultRows = buildDefaultPricingMethodDetailRows(serviceId, context)
|
||||
console.log('[pricing][ensure-detail-rows][defaults] ' + JSON.stringify({
|
||||
contractId: params.contractId,
|
||||
serviceId,
|
||||
lengths: {
|
||||
invest: Array.isArray(defaultRows.investScale) ? defaultRows.investScale.length : -1,
|
||||
land: Array.isArray(defaultRows.landScale) ? defaultRows.landScale.length : -1,
|
||||
workload: Array.isArray(defaultRows.workload) ? defaultRows.workload.length : -1,
|
||||
hourly: Array.isArray(defaultRows.hourly) ? defaultRows.hourly.length : -1
|
||||
},
|
||||
sample: {
|
||||
invest: Array.isArray(defaultRows.investScale) ? defaultRows.investScale[0] : null,
|
||||
land: Array.isArray(defaultRows.landScale) ? defaultRows.landScale[0] : null,
|
||||
workload: Array.isArray(defaultRows.workload) ? defaultRows.workload[0] : null,
|
||||
hourly: Array.isArray(defaultRows.hourly) ? defaultRows.hourly[0] : null
|
||||
}
|
||||
}))
|
||||
}
|
||||
return defaultRows
|
||||
}
|
||||
@ -997,6 +1046,13 @@ export const ensurePricingMethodDetailRowsForServices = async (params: {
|
||||
if (writeTasks.length > 0) {
|
||||
await Promise.all(writeTasks)
|
||||
}
|
||||
|
||||
console.log('[pricing][ensure-detail-rows][after] ' + JSON.stringify({
|
||||
contractId: params.contractId,
|
||||
serviceId,
|
||||
wroteAny: writeTasks.length > 0,
|
||||
writeCount: writeTasks.length
|
||||
}))
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
@ -294,10 +294,10 @@ export const initializeProjectFactorStates = async (
|
||||
detailRows: buildFactorRowsFromEntries(majorEntries)
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
kvStore.setItem(consultCategoryFactorKey, consultPayload),
|
||||
kvStore.setItem(majorFactorKey, majorPayload)
|
||||
])
|
||||
// 新项目初始化走 createProjectKvAdapter 时,setItem 是整包读改写,不是原子更新。
|
||||
// 这里并发写两个 key 会互相覆盖,导致咨询系数或专业系数其中一个丢失。
|
||||
await kvStore.setItem(consultCategoryFactorKey, consultPayload)
|
||||
await kvStore.setItem(majorFactorKey, majorPayload)
|
||||
}
|
||||
|
||||
export const initializeProjectScaleState = async (
|
||||
@ -307,3 +307,4 @@ export const initializeProjectScaleState = async (
|
||||
) => {
|
||||
await kvStore.setItem(projectScaleKey, buildDefaultProjectScaleState(industry))
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { serviceList } from '@/sql'
|
||||
import { getMajorDictById, getMajorIdAliasMap, serviceList } from '@/sql'
|
||||
import { roundTo, toFiniteNumber, toFiniteNumberOrZero } from '@/lib/decimal'
|
||||
import { getBenchmarkBudgetSplitByScale, getScaleBudgetFeeSplit } from '@/lib/pricingScaleFee'
|
||||
export { toFiniteNumber, toFiniteNumberOrZero }
|
||||
@ -52,6 +52,7 @@ interface ScaleRowLike {
|
||||
|
||||
interface WorkloadMethodRowLike {
|
||||
id: string
|
||||
conversion?: unknown
|
||||
budgetAdoptedUnitPrice?: unknown
|
||||
workload?: unknown
|
||||
basicFee?: unknown
|
||||
@ -246,6 +247,18 @@ export const toScaleMajorId = (row: ScaleMethodRowLike): number | null => {
|
||||
return toSafeInteger(parsed.majorPart)
|
||||
}
|
||||
|
||||
const majorDictById = getMajorDictById() as Record<string, { hasCost?: unknown; hasArea?: unknown } | undefined>
|
||||
const majorIdAliasMap = getMajorIdAliasMap()
|
||||
|
||||
const resolveMajorCapability = (majorId: number | null) => {
|
||||
if (majorId == null) return null
|
||||
const key = String(majorId)
|
||||
const resolvedKey = Object.prototype.hasOwnProperty.call(majorDictById, key)
|
||||
? key
|
||||
: (majorIdAliasMap.get(key) || key)
|
||||
return majorDictById[resolvedKey] || null
|
||||
}
|
||||
|
||||
export const toScaleProNum = (row: ScaleMethodRowLike): number => {
|
||||
const parsed = parseScaleScopedRowId(row.id)
|
||||
return parsed.proNum > 0 ? parsed.proNum : 1
|
||||
@ -276,7 +289,16 @@ const isExportableScaleMethodRow = (
|
||||
mode: 'cost' | 'area'
|
||||
) => {
|
||||
if (!isScaleLeafRow(row)) return false
|
||||
return mode === 'cost' ? row?.hasCost === true : row?.hasArea === true
|
||||
if (mode === 'cost') {
|
||||
if (row?.hasCost === true) return true
|
||||
if (row?.hasCost === false) return false
|
||||
} else {
|
||||
if (row?.hasArea === true) return true
|
||||
if (row?.hasArea === false) return false
|
||||
}
|
||||
const major = row ? resolveMajorCapability(toScaleMajorId(row)) : null
|
||||
if (!major) return false
|
||||
return mode === 'cost' ? major.hasCost !== false : major.hasArea !== false
|
||||
}
|
||||
|
||||
export const normalizeTaskText = (value: unknown): string => String(value || '').trim()
|
||||
@ -527,16 +549,34 @@ export const buildMethod2 = (rows: ScaleMethodRowLike[] | undefined) => {
|
||||
}
|
||||
}
|
||||
|
||||
const resolveWorkloadBasicFee = (row: WorkloadMethodRowLike) => {
|
||||
const basicFee = toFiniteNumber(row.basicFee)
|
||||
if (basicFee != null) return basicFee
|
||||
const price = toFiniteNumber(row.budgetAdoptedUnitPrice)
|
||||
const conversion = toFiniteNumber(row.conversion)
|
||||
const amount = toFiniteNumber(row.workload)
|
||||
if (price == null || conversion == null || amount == null) return null
|
||||
return roundTo(price * conversion * amount, 2)
|
||||
}
|
||||
|
||||
const resolveWorkloadServiceFee = (row: WorkloadMethodRowLike, basicFee: number | null) => {
|
||||
const fee = toFiniteNumber(row.serviceFee)
|
||||
if (fee != null) return fee
|
||||
const factor = toFiniteNumber(row.consultCategoryFactor)
|
||||
if (basicFee == null || factor == null) return null
|
||||
return roundTo(basicFee * factor, 2)
|
||||
}
|
||||
|
||||
export const buildMethod3 = (rows: WorkloadMethodRowLike[] | undefined) => {
|
||||
if (!Array.isArray(rows)) return null
|
||||
let hasTotalValue = false
|
||||
const det = rows
|
||||
.map(row => {
|
||||
const task = getTaskIdFromRowId(row.id)
|
||||
if (task == null || row.basicFee == null) return null
|
||||
if (task == null) return null
|
||||
const amount = toFiniteNumber(row.workload)
|
||||
const basicFee = toFiniteNumber(row.basicFee)
|
||||
const fee = toFiniteNumber(row.serviceFee)
|
||||
const basicFee = resolveWorkloadBasicFee(row)
|
||||
const fee = resolveWorkloadServiceFee(row, basicFee)
|
||||
if (fee != null) hasTotalValue = true
|
||||
const remark = typeof row.remark === 'string' ? row.remark : ''
|
||||
const hasValue = amount != null || basicFee != null || fee != null || isNonEmptyString(remark)
|
||||
@ -561,16 +601,26 @@ export const buildMethod3 = (rows: WorkloadMethodRowLike[] | undefined) => {
|
||||
}
|
||||
}
|
||||
|
||||
const resolveHourlyServiceFee = (row: HourlyMethodRowLike) => {
|
||||
const fee = toFiniteNumber(row.serviceBudget)
|
||||
if (fee != null) return fee
|
||||
const price = toFiniteNumber(row.adoptedBudgetUnitPrice)
|
||||
const personNum = toFiniteNumber(row.personnelCount)
|
||||
const workDay = toFiniteNumber(row.workdayCount)
|
||||
if (price == null || personNum == null || workDay == null) return null
|
||||
return roundTo(price * personNum * workDay, 2)
|
||||
}
|
||||
|
||||
export const buildMethod4 = (rows: HourlyMethodRowLike[] | undefined) => {
|
||||
if (!Array.isArray(rows)) return null
|
||||
let hasTotalValue = false
|
||||
const det = rows
|
||||
.map(row => {
|
||||
const expert = getExpertIdFromRowId(row.id)
|
||||
if (expert == null || row.serviceBudget == null) return null
|
||||
if (expert == null) return null
|
||||
const personNum = toFiniteNumber(row.personnelCount)
|
||||
const workDay = toFiniteNumber(row.workdayCount)
|
||||
const fee = toFiniteNumber(row.serviceBudget)
|
||||
const fee = resolveHourlyServiceFee(row)
|
||||
if (fee != null) hasTotalValue = true
|
||||
const remark = typeof row.remark === 'string' ? row.remark : ''
|
||||
const hasValue = personNum != null || workDay != null || fee != null || isNonEmptyString(remark)
|
||||
|
||||
@ -22,6 +22,15 @@ type FactorDictItem = {
|
||||
|
||||
type FactorDict = Record<string, FactorDictItem>
|
||||
|
||||
const hasUsableFactorRows = (state: XmFactorState | null | undefined) =>
|
||||
Array.isArray(state?.detailRows) &&
|
||||
state.detailRows.some(row => {
|
||||
const hasFactor =
|
||||
toFiniteNumberOrNull(row?.budgetValue) != null ||
|
||||
toFiniteNumberOrNull(row?.standardFactor) != null
|
||||
return hasFactor || String(row?.id || '').trim() !== ''
|
||||
})
|
||||
|
||||
const buildStandardFactorMap = (dict: FactorDict): Map<string, number | null> => {
|
||||
const map = new Map<string, number | null>()
|
||||
for (const [id, item] of Object.entries(dict)) {
|
||||
@ -68,7 +77,12 @@ const loadFactorMap = async (
|
||||
const zxFwPricingStore = getZxFwPricingStoreSafely()
|
||||
const kvStore = getKvStoreSafely()
|
||||
const piniaData = zxFwPricingStore ? await zxFwPricingStore.loadKeyState<XmFactorState>(storageKey) : null
|
||||
const data = piniaData ?? (kvStore ? await kvStore.getItem<XmFactorState>(storageKey) : null)
|
||||
const kvData = kvStore ? await kvStore.getItem<XmFactorState>(storageKey) : null
|
||||
const data = hasUsableFactorRows(piniaData)
|
||||
? piniaData
|
||||
: hasUsableFactorRows(kvData)
|
||||
? kvData
|
||||
: (piniaData ?? kvData)
|
||||
const map = buildStandardFactorMap(dict)
|
||||
for (const row of data?.detailRows || []) {
|
||||
if (!row?.id) continue
|
||||
|
||||
@ -1864,6 +1864,8 @@ export function getBasicFeeFromScale(
|
||||
* @returns 导出流程完成后的 Promise
|
||||
*/
|
||||
export async function exportFile(fileName: string, data: any | (() => Promise<any>), onSaveConfirmed?: () => void): Promise<string | null> {
|
||||
|
||||
|
||||
if (window.showSaveFilePicker) {
|
||||
const handle = await window.showSaveFilePicker({
|
||||
suggestedName: fileName,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user