完成大部分
This commit is contained in:
1 parent
e97707ac59
commit
13b03e016e
21 files changed
+1628
-275
No files matched your search
@@ -3,10 +3,13 @@ import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import { AgGridVue } from 'ag-grid-vue3'
|
||||
import type { ColDef } from 'ag-grid-community'
|
||||
import localforage from 'localforage'
|
||||
import { getBasicFeeFromScale, majorList, serviceList } from '@/sql'
|
||||
import { getBasicFeeFromScale, majorList } from '@/sql'
|
||||
import { myTheme, gridOptions } from '@/lib/diyAgGridOptions'
|
||||
import { addNumbers, decimalAggSum, roundTo, sumByNumber, toDecimal } from '@/lib/decimal'
|
||||
import { formatThousands } from '@/lib/numberFormat'
|
||||
import { syncPricingTotalToZxFw, ZXFW_RELOAD_SERVICE_KEY } from '@/lib/zxFwPricingSync'
|
||||
import { usePricingPaneReloadStore } from '@/pinia/pricingPaneReload'
|
||||
import { loadConsultCategoryFactorMap, loadMajorFactorMap } from '@/lib/xmFactorDefaults'
|
||||
|
||||
import { AG_GRID_LOCALE_CN } from '@ag-grid-community/locale';
|
||||
// 精简的边框配置(细线条+浅灰色,弱化分割线视觉)
|
||||
@@ -53,6 +56,25 @@ const HT_DB_KEY = computed(() => `ht-info-v3-${props.contractId}`)
|
||||
const PRICING_CLEAR_SKIP_PREFIX = 'pricing-clear-skip:'
|
||||
const PRICING_FORCE_DEFAULT_PREFIX = 'pricing-force-default:'
|
||||
const pricingPaneReloadStore = usePricingPaneReloadStore()
|
||||
const consultCategoryFactorMap = ref<Map<string, number | null>>(new Map())
|
||||
const majorFactorMap = ref<Map<string, number | null>>(new Map())
|
||||
let factorDefaultsLoaded = false
|
||||
|
||||
const getDefaultConsultCategoryFactor = () =>
|
||||
consultCategoryFactorMap.value.get(String(props.serviceId)) ?? null
|
||||
|
||||
const getDefaultMajorFactorById = (id: string): number | null => majorFactorMap.value.get(id) ?? null
|
||||
|
||||
const ensureFactorDefaultsLoaded = async () => {
|
||||
if (factorDefaultsLoaded) return
|
||||
const [consultMap, majorMap] = await Promise.all([
|
||||
loadConsultCategoryFactorMap(),
|
||||
loadMajorFactorMap()
|
||||
])
|
||||
consultCategoryFactorMap.value = consultMap
|
||||
majorFactorMap.value = majorMap
|
||||
factorDefaultsLoaded = true
|
||||
}
|
||||
|
||||
const shouldSkipPersist = () => {
|
||||
const storageKey = `${PRICING_CLEAR_SKIP_PREFIX}${DB_KEY.value}`
|
||||
@@ -74,12 +96,6 @@ const shouldForceDefaultLoad = () => {
|
||||
}
|
||||
|
||||
const detailRows = ref<DetailRow[]>([])
|
||||
type serviceLite = { defCoe: number | null }
|
||||
const defaultConsultCategoryFactor = computed<number | null>(() => {
|
||||
const service = (serviceList as Record<string, serviceLite | undefined>)[String(props.serviceId)]
|
||||
return typeof service?.defCoe === 'number' && Number.isFinite(service.defCoe) ? service.defCoe : null
|
||||
})
|
||||
|
||||
type majorLite = { code: string; name: string; defCoe: number | null }
|
||||
const serviceEntries = Object.entries(majorList as Record<string, majorLite>)
|
||||
.sort((a, b) => Number(a[0]) - Number(b[0]))
|
||||
@@ -88,11 +104,6 @@ const serviceEntries = Object.entries(majorList as Record<string, majorLite>)
|
||||
return Boolean(item?.code && item?.name)
|
||||
})
|
||||
|
||||
const getDefaultMajorFactorById = (id: string): number | null => {
|
||||
const major = (majorList as Record<string, majorLite | undefined>)[id]
|
||||
return typeof major?.defCoe === 'number' && Number.isFinite(major.defCoe) ? major.defCoe : null
|
||||
}
|
||||
|
||||
const detailDict: DictGroup[] = (() => {
|
||||
const groupMap = new Map<string, DictGroup>()
|
||||
const groupOrder: string[] = []
|
||||
@@ -154,7 +165,7 @@ const buildDefaultRows = (): DetailRow[] => {
|
||||
majorName: child.name,
|
||||
amount: null,
|
||||
benchmarkBudget: null,
|
||||
consultCategoryFactor: defaultConsultCategoryFactor.value,
|
||||
consultCategoryFactor: getDefaultConsultCategoryFactor(),
|
||||
majorFactor: getDefaultMajorFactorById(child.id),
|
||||
budgetFee: null,
|
||||
remark: '',
|
||||
@@ -187,7 +198,7 @@ const mergeWithDictRows = (rowsFromDb: SourceRow[] | undefined): DetailRow[] =>
|
||||
? fromDb.consultCategoryFactor
|
||||
: hasConsultCategoryFactor
|
||||
? null
|
||||
: defaultConsultCategoryFactor.value,
|
||||
: getDefaultConsultCategoryFactor(),
|
||||
majorFactor:
|
||||
typeof fromDb.majorFactor === 'number'
|
||||
? fromDb.majorFactor
|
||||
@@ -216,8 +227,9 @@ const formatEditableNumber = (params: any) => {
|
||||
|
||||
const formatConsultCategoryFactor = (params: any) => {
|
||||
if (params.node?.group) {
|
||||
if (defaultConsultCategoryFactor.value == null) return ''
|
||||
return Number(defaultConsultCategoryFactor.value).toFixed(2)
|
||||
const v = getDefaultConsultCategoryFactor()
|
||||
if (v == null) return ''
|
||||
return Number(v).toFixed(2)
|
||||
}
|
||||
return formatEditableNumber(params)
|
||||
}
|
||||
@@ -232,9 +244,17 @@ const formatMajorFactor = (params: any) => {
|
||||
return formatEditableNumber(params)
|
||||
}
|
||||
|
||||
const formatReadonlyNumber = (params: any) => {
|
||||
const formatEditableMoney = (params: any) => {
|
||||
if (!params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')) {
|
||||
return '点击输入'
|
||||
}
|
||||
if (params.value == null) return ''
|
||||
return formatThousands(params.value)
|
||||
}
|
||||
|
||||
const formatReadonlyMoney = (params: any) => {
|
||||
if (params.value == null || params.value === '') return ''
|
||||
return roundTo(params.value, 2).toFixed(2)
|
||||
return formatThousands(roundTo(params.value, 2))
|
||||
}
|
||||
|
||||
const getBenchmarkBudgetByAmount = (row?: Pick<DetailRow, 'amount'>) => {
|
||||
@@ -252,34 +272,38 @@ const columnDefs: ColDef<DetailRow>[] = [
|
||||
{
|
||||
headerName: '造价金额(万元)',
|
||||
field: 'amount',
|
||||
minWidth: 170,
|
||||
flex: 1,
|
||||
headerClass: 'ag-right-aligned-header',
|
||||
minWidth: 100,
|
||||
flex: 2,
|
||||
|
||||
editable: params => !params.node?.group && !params.node?.rowPinned,
|
||||
cellClass: params => (!params.node?.group && !params.node?.rowPinned ? 'editable-cell-line' : ''),
|
||||
cellClass: params => (!params.node?.group && !params.node?.rowPinned ? 'ag-right-aligned-cell editable-cell-line' : 'ag-right-aligned-cell'),
|
||||
cellClassRules: {
|
||||
'editable-cell-empty': params =>
|
||||
!params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
|
||||
},
|
||||
aggFunc: decimalAggSum,
|
||||
valueParser: params => parseNumberOrNull(params.newValue),
|
||||
valueFormatter: formatEditableNumber
|
||||
valueFormatter: formatEditableMoney
|
||||
},
|
||||
{
|
||||
headerName: '基准预算(元)',
|
||||
field: 'benchmarkBudget',
|
||||
minWidth: 170,
|
||||
flex: 1,
|
||||
headerClass: 'ag-right-aligned-header',
|
||||
minWidth: 100,
|
||||
flex: 2,
|
||||
cellClass: 'ag-right-aligned-cell',
|
||||
aggFunc: decimalAggSum,
|
||||
valueGetter: params => getBenchmarkBudgetByAmount(params.data),
|
||||
valueParser: params => parseNumberOrNull(params.newValue),
|
||||
valueFormatter: formatReadonlyNumber
|
||||
valueFormatter: formatReadonlyMoney
|
||||
},
|
||||
{
|
||||
headerName: '咨询分类系数',
|
||||
field: 'consultCategoryFactor',
|
||||
minWidth: 150,
|
||||
flex: 1,
|
||||
width: 80,
|
||||
minWidth: 70,
|
||||
maxWidth: 90,
|
||||
editable: params => !params.node?.group && !params.node?.rowPinned,
|
||||
cellClass: params => (!params.node?.group && !params.node?.rowPinned ? 'editable-cell-line' : ''),
|
||||
cellClassRules: {
|
||||
@@ -292,8 +316,9 @@ const columnDefs: ColDef<DetailRow>[] = [
|
||||
{
|
||||
headerName: '专业系数',
|
||||
field: 'majorFactor',
|
||||
minWidth: 130,
|
||||
flex: 1,
|
||||
width: 80,
|
||||
minWidth: 70,
|
||||
maxWidth: 90,
|
||||
editable: params => !params.node?.group && !params.node?.rowPinned,
|
||||
cellClass: params => (!params.node?.group && !params.node?.rowPinned ? 'editable-cell-line' : ''),
|
||||
cellClassRules: {
|
||||
@@ -306,12 +331,14 @@ const columnDefs: ColDef<DetailRow>[] = [
|
||||
{
|
||||
headerName: '预算费用',
|
||||
field: 'budgetFee',
|
||||
minWidth: 150,
|
||||
flex: 1,
|
||||
headerClass: 'ag-right-aligned-header',
|
||||
minWidth: 100,
|
||||
flex:2,
|
||||
cellClass: 'ag-right-aligned-cell',
|
||||
aggFunc: decimalAggSum,
|
||||
valueGetter: params => (params.node?.rowPinned ? params.data?.budgetFee ?? null : getBudgetFee(params.data)),
|
||||
valueParser: params => parseNumberOrNull(params.newValue),
|
||||
valueFormatter: formatReadonlyNumber
|
||||
valueFormatter: formatReadonlyMoney
|
||||
},
|
||||
{
|
||||
headerName: '说明',
|
||||
@@ -338,10 +365,13 @@ const columnDefs: ColDef<DetailRow>[] = [
|
||||
|
||||
const autoGroupColumnDef: ColDef = {
|
||||
headerName: '专业编码以及工程专业名称',
|
||||
minWidth: 320,
|
||||
minWidth: 250,
|
||||
pinned: 'left',
|
||||
flex: 2,
|
||||
// wrapText: true,
|
||||
// cellStyle: { whiteSpace: 'normal', lineHeight: '1.5', padding: '2px' },
|
||||
|
||||
// autoHeight: true,
|
||||
cellRendererParams: {
|
||||
suppressCount: true
|
||||
},
|
||||
@@ -351,6 +381,11 @@ const autoGroupColumnDef: ColDef = {
|
||||
}
|
||||
const nodeId = String(params.value || '')
|
||||
return idLabelMap.get(nodeId) || nodeId
|
||||
},
|
||||
tooltipValueGetter: params => {
|
||||
if (params.node?.rowPinned) return '总合计'
|
||||
const nodeId = String(params.value || '')
|
||||
return idLabelMap.get(nodeId) || nodeId
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,6 +422,15 @@ const saveToIndexedDB = async () => {
|
||||
}
|
||||
console.log('Saving to IndexedDB:', payload)
|
||||
await localforage.setItem(DB_KEY.value, payload)
|
||||
const synced = await syncPricingTotalToZxFw({
|
||||
contractId: props.contractId,
|
||||
serviceId: props.serviceId,
|
||||
field: 'investScale',
|
||||
value: totalBudgetFee.value
|
||||
})
|
||||
if (synced) {
|
||||
pricingPaneReloadStore.markReload(props.contractId, ZXFW_RELOAD_SERVICE_KEY)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('saveToIndexedDB failed:', error)
|
||||
}
|
||||
@@ -394,6 +438,7 @@ const saveToIndexedDB = async () => {
|
||||
|
||||
const loadFromIndexedDB = async () => {
|
||||
try {
|
||||
await ensureFactorDefaultsLoaded()
|
||||
if (shouldForceDefaultLoad()) {
|
||||
const htData = await localforage.getItem<{ detailRows: SourceRow[] }>(HT_DB_KEY.value)
|
||||
detailRows.value = htData?.detailRows ? mergeWithDictRows(htData.detailRows) : buildDefaultRows()
|
||||
@@ -465,6 +510,8 @@ const processCellFromClipboard = (params: any) => {
|
||||
}
|
||||
return params.value;
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
Reference in new issue
Block a user