优化
This commit is contained in:
parent
3dce3646e1
commit
c4d04cbee3
1
bun.lock
1
bun.lock
@ -11,7 +11,6 @@
|
||||
"@internationalized/number": "^3.6.5",
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"@vueuse/core": "^14.2.1",
|
||||
"ag-grid-community": "^35.1.0",
|
||||
"ag-grid-enterprise": "^35.1.0",
|
||||
"ag-grid-vue3": "^35.1.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
"@internationalized/number": "^3.6.5",
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"@vueuse/core": "^14.2.1",
|
||||
"ag-grid-community": "^35.1.0",
|
||||
"ag-grid-enterprise": "^35.1.0",
|
||||
"ag-grid-vue3": "^35.1.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onActivated, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { AgGridVue } from 'ag-grid-vue3'
|
||||
import type { ColDef, ColGroupDef } from 'ag-grid-community'
|
||||
import type { ColDef, ColGroupDef, GridApi, GridReadyEvent } from 'ag-grid-community'
|
||||
import { getMajorDictEntries, getServiceDictItemById, industryTypeList, isMajorIdInIndustryScope } from '@/sql'
|
||||
import { myTheme, gridOptions, agGridWrapClass, agGridStyle } from '@/lib/diyAgGridOptions'
|
||||
import { addNumbers, decimalAggSum, roundTo, sumByNumber } from '@/lib/decimal'
|
||||
@ -108,6 +108,7 @@ const consultCategoryFactorMap = ref<Map<string, number | null>>(new Map())
|
||||
const majorFactorMap = ref<Map<string, number | null>>(new Map())
|
||||
let factorDefaultsLoaded = false
|
||||
const paneInstanceCreatedAt = Date.now()
|
||||
const gridApi = ref<GridApi<DetailRow> | null>(null)
|
||||
const ONLY_COST_SCALE_ROW_ID = '__only-cost-scale-total__'
|
||||
const industryNameMap = new Map(
|
||||
industryTypeList.flatMap(item => [
|
||||
@ -832,13 +833,14 @@ const columnDefs: Array<ColDef<DetailRow> | ColGroupDef<DetailRow>> = [
|
||||
headerName: '咨询分类系数',
|
||||
field: 'consultCategoryFactor',
|
||||
colId: 'consultCategoryFactor',
|
||||
headerClass: 'ag-right-aligned-header',
|
||||
minWidth: 80,
|
||||
flex: 1,
|
||||
editable: params => !params.node?.group && !params.node?.rowPinned,
|
||||
cellClass: params =>
|
||||
!params.node?.group && !params.node?.rowPinned
|
||||
? 'editable-cell-line'
|
||||
: '',
|
||||
? '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 === '')
|
||||
@ -850,13 +852,14 @@ const columnDefs: Array<ColDef<DetailRow> | ColGroupDef<DetailRow>> = [
|
||||
headerName: '专业系数',
|
||||
field: 'majorFactor',
|
||||
colId: 'majorFactor',
|
||||
headerClass: 'ag-right-aligned-header',
|
||||
minWidth: 80,
|
||||
flex: 1,
|
||||
editable: params => !params.node?.group && !params.node?.rowPinned,
|
||||
cellClass: params =>
|
||||
!params.node?.group && !params.node?.rowPinned
|
||||
? 'editable-cell-line'
|
||||
: '',
|
||||
? '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 === '')
|
||||
@ -868,13 +871,14 @@ const columnDefs: Array<ColDef<DetailRow> | ColGroupDef<DetailRow>> = [
|
||||
headerName: '工作环节系数(编审系数)',
|
||||
field: 'workStageFactor',
|
||||
colId: 'workStageFactor',
|
||||
headerClass: 'ag-right-aligned-header',
|
||||
minWidth: 80,
|
||||
flex: 1,
|
||||
editable: params => !params.node?.group && !params.node?.rowPinned,
|
||||
cellClass: params =>
|
||||
!params.node?.group && !params.node?.rowPinned
|
||||
? 'editable-cell-line'
|
||||
: '',
|
||||
? '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 === '')
|
||||
@ -886,13 +890,14 @@ const columnDefs: Array<ColDef<DetailRow> | ColGroupDef<DetailRow>> = [
|
||||
headerName: '工作占比(%)',
|
||||
field: 'workRatio',
|
||||
colId: 'workRatio',
|
||||
headerClass: 'ag-right-aligned-header',
|
||||
minWidth: 80,
|
||||
flex: 1,
|
||||
editable: params => !params.node?.group && !params.node?.rowPinned,
|
||||
cellClass: params =>
|
||||
!params.node?.group && !params.node?.rowPinned
|
||||
? 'editable-cell-line'
|
||||
: '',
|
||||
? '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 === '')
|
||||
@ -1065,7 +1070,13 @@ const saveToIndexedDB = async () => {
|
||||
detailRows: JSON.parse(JSON.stringify(buildPersistDetailRows())),
|
||||
projectCount: getTargetProjectCount()
|
||||
}
|
||||
zxFwPricingStore.setServicePricingMethodState(props.contractId, props.serviceId, 'investScale', payload)
|
||||
zxFwPricingStore.setServicePricingMethodState(
|
||||
props.contractId,
|
||||
props.serviceId,
|
||||
'investScale',
|
||||
payload,
|
||||
{ force: true }
|
||||
)
|
||||
const synced = await syncPricingTotalToZxFw({
|
||||
contractId: props.contractId,
|
||||
serviceId: props.serviceId,
|
||||
@ -1274,6 +1285,10 @@ const handleCellValueChanged = () => {
|
||||
void saveToIndexedDB()
|
||||
}
|
||||
|
||||
const handleGridReady = (event: GridReadyEvent<DetailRow>) => {
|
||||
gridApi.value = event.api
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await loadFromIndexedDB()
|
||||
})
|
||||
@ -1283,6 +1298,8 @@ onActivated(() => {
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
gridApi.value?.stopEditing()
|
||||
gridApi.value = null
|
||||
void saveToIndexedDB()
|
||||
})
|
||||
const processCellForClipboard = (params: any) => {
|
||||
@ -1380,6 +1397,7 @@ const processCellFromClipboard = (params: any) => {
|
||||
<AgGridVue :style="agGridStyle" :rowData="detailRows" :pinnedTopRowData="pinnedTopRowData"
|
||||
:columnDefs="columnDefs" :autoGroupColumnDef="autoGroupColumnDef" :gridOptions="gridOptions" :theme="myTheme"
|
||||
:animateRows="true"
|
||||
@grid-ready="handleGridReady"
|
||||
@cell-value-changed="handleCellValueChanged" :suppressColumnVirtualisation="true"
|
||||
:suppressRowVirtualisation="true" :cellSelection="{ handle: { mode: 'range' } }" :enableClipboard="true"
|
||||
:localeText="AG_GRID_LOCALE_CN" :tooltipShowDelay="500" :headerHeight="50"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onActivated, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { AgGridVue } from 'ag-grid-vue3'
|
||||
import type { ColDef, ColGroupDef } from 'ag-grid-community'
|
||||
import type { ColDef, ColGroupDef, GridApi, GridReadyEvent } from 'ag-grid-community'
|
||||
import { getMajorDictEntries, getServiceDictItemById, industryTypeList, isMajorIdInIndustryScope } from '@/sql'
|
||||
import { myTheme, gridOptions, agGridWrapClass, agGridStyle } from '@/lib/diyAgGridOptions'
|
||||
import { addNumbers, decimalAggSum, roundTo, sumByNumber } from '@/lib/decimal'
|
||||
@ -108,6 +108,7 @@ const consultCategoryFactorMap = ref<Map<string, number | null>>(new Map())
|
||||
const majorFactorMap = ref<Map<string, number | null>>(new Map())
|
||||
let factorDefaultsLoaded = false
|
||||
const paneInstanceCreatedAt = Date.now()
|
||||
const gridApi = ref<GridApi<DetailRow> | null>(null)
|
||||
const industryNameMap = new Map(
|
||||
industryTypeList.flatMap(item => [
|
||||
[String(item.id).trim(), item.name],
|
||||
@ -708,10 +709,14 @@ const columnDefs: Array<ColDef<DetailRow> | ColGroupDef<DetailRow>> = [
|
||||
headerName: '咨询分类系数',
|
||||
field: 'consultCategoryFactor',
|
||||
colId: 'consultCategoryFactor',
|
||||
headerClass: 'ag-right-aligned-header',
|
||||
minWidth: 80,
|
||||
flex: 1,
|
||||
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 === '')
|
||||
@ -723,10 +728,14 @@ const columnDefs: Array<ColDef<DetailRow> | ColGroupDef<DetailRow>> = [
|
||||
headerName: '专业系数',
|
||||
field: 'majorFactor',
|
||||
colId: 'majorFactor',
|
||||
headerClass: 'ag-right-aligned-header',
|
||||
minWidth: 80,
|
||||
flex: 1,
|
||||
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 === '')
|
||||
@ -738,10 +747,14 @@ const columnDefs: Array<ColDef<DetailRow> | ColGroupDef<DetailRow>> = [
|
||||
headerName: '工作环节系数(编审系数)',
|
||||
field: 'workStageFactor',
|
||||
colId: 'workStageFactor',
|
||||
headerClass: 'ag-right-aligned-header',
|
||||
minWidth: 80,
|
||||
flex: 1,
|
||||
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 === '')
|
||||
@ -753,10 +766,14 @@ const columnDefs: Array<ColDef<DetailRow> | ColGroupDef<DetailRow>> = [
|
||||
headerName: '工作占比(%)',
|
||||
field: 'workRatio',
|
||||
colId: 'workRatio',
|
||||
headerClass: 'ag-right-aligned-header',
|
||||
minWidth: 80,
|
||||
flex: 1,
|
||||
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 === '')
|
||||
@ -930,7 +947,13 @@ const saveToIndexedDB = async () => {
|
||||
detailRows: JSON.parse(JSON.stringify(buildPersistDetailRows())),
|
||||
projectCount: getTargetProjectCount()
|
||||
}
|
||||
zxFwPricingStore.setServicePricingMethodState(props.contractId, props.serviceId, 'landScale', payload)
|
||||
zxFwPricingStore.setServicePricingMethodState(
|
||||
props.contractId,
|
||||
props.serviceId,
|
||||
'landScale',
|
||||
payload,
|
||||
{ force: true }
|
||||
)
|
||||
const synced = await syncPricingTotalToZxFw({
|
||||
contractId: props.contractId,
|
||||
serviceId: props.serviceId,
|
||||
@ -1111,6 +1134,10 @@ const handleCellValueChanged = () => {
|
||||
void saveToIndexedDB()
|
||||
}
|
||||
|
||||
const handleGridReady = (event: GridReadyEvent<DetailRow>) => {
|
||||
gridApi.value = event.api
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await loadFromIndexedDB()
|
||||
})
|
||||
@ -1120,6 +1147,8 @@ onActivated(() => {
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
gridApi.value?.stopEditing()
|
||||
gridApi.value = null
|
||||
void saveToIndexedDB()
|
||||
})
|
||||
const processCellForClipboard = (params: any) => {
|
||||
@ -1219,6 +1248,7 @@ const processCellFromClipboard = (params: any) => {
|
||||
<AgGridVue :style="agGridStyle" :rowData="detailRows" :pinnedTopRowData="pinnedTopRowData"
|
||||
:columnDefs="columnDefs" :autoGroupColumnDef="autoGroupColumnDef" :gridOptions="gridOptions" :theme="myTheme"
|
||||
:animateRows="true"
|
||||
@grid-ready="handleGridReady"
|
||||
@cell-value-changed="handleCellValueChanged" :suppressColumnVirtualisation="true"
|
||||
:suppressRowVirtualisation="true" :cellSelection="{ handle: { mode: 'range' } }" :enableClipboard="true"
|
||||
:localeText="AG_GRID_LOCALE_CN" :tooltipShowDelay="500" :headerHeight="50"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { AgGridVue } from 'ag-grid-vue3'
|
||||
import type { ColDef } from 'ag-grid-community'
|
||||
import type { ColDef, GridApi, GridReadyEvent } from 'ag-grid-community'
|
||||
import { taskList } from '@/sql'
|
||||
import { myTheme, gridOptions, agGridWrapClass, agGridStyle } from '@/lib/diyAgGridOptions'
|
||||
import { decimalAggSum, roundTo, sumByNumber, toDecimal } from '@/lib/decimal'
|
||||
@ -49,6 +49,7 @@ const PRICING_FORCE_DEFAULT_PREFIX = 'pricing-force-default:'
|
||||
const consultCategoryFactorMap = ref<Map<string, number | null>>(new Map())
|
||||
let factorDefaultsLoaded = false
|
||||
const paneInstanceCreatedAt = Date.now()
|
||||
const gridApi = ref<GridApi<DetailRow> | null>(null)
|
||||
|
||||
const getDefaultConsultCategoryFactor = () =>
|
||||
consultCategoryFactorMap.value.get(String(props.serviceId)) ?? null
|
||||
@ -183,6 +184,7 @@ const mergeWithDictRows = (rowsFromDb: DetailRow[] | undefined): DetailRow[] =>
|
||||
return buildDefaultRows().map(row => {
|
||||
const fromDb = dbValueMap.get(row.id)
|
||||
if (!fromDb) return row
|
||||
const hasRemark = Object.prototype.hasOwnProperty.call(fromDb, 'remark')
|
||||
|
||||
return {
|
||||
...row,
|
||||
@ -193,7 +195,7 @@ const mergeWithDictRows = (rowsFromDb: DetailRow[] | undefined): DetailRow[] =>
|
||||
consultCategoryFactor:
|
||||
typeof fromDb.consultCategoryFactor === 'number' ? fromDb.consultCategoryFactor : null,
|
||||
serviceFee: typeof fromDb.serviceFee === 'number' ? fromDb.serviceFee : null,
|
||||
remark: typeof fromDb.remark === 'string' ? fromDb.remark : ''
|
||||
remark: typeof fromDb.remark === 'string' ? fromDb.remark : hasRemark ? '' : row.remark
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -270,7 +272,9 @@ const columnDefs: ColDef<DetailRow>[] = [
|
||||
minWidth: 150,
|
||||
width: 220,
|
||||
pinned: 'left',
|
||||
autoHeight: true,
|
||||
wrapText: true,
|
||||
autoHeight: true,
|
||||
cellStyle: { whiteSpace: 'normal', lineHeight: '1.4' },
|
||||
|
||||
spanRows: true,
|
||||
valueFormatter: params => (params.node?.rowPinned ? '' : params.value || '')
|
||||
@ -445,7 +449,13 @@ const saveToIndexedDB = async () => {
|
||||
const payload = {
|
||||
detailRows: JSON.parse(JSON.stringify(buildPersistDetailRows()))
|
||||
}
|
||||
zxFwPricingStore.setServicePricingMethodState(props.contractId, props.serviceId, 'workload', payload)
|
||||
zxFwPricingStore.setServicePricingMethodState(
|
||||
props.contractId,
|
||||
props.serviceId,
|
||||
'workload',
|
||||
payload,
|
||||
{ force: true }
|
||||
)
|
||||
const synced = await syncPricingTotalToZxFw({
|
||||
contractId: props.contractId,
|
||||
serviceId: props.serviceId,
|
||||
@ -489,11 +499,17 @@ const handleCellValueChanged = () => {
|
||||
void saveToIndexedDB()
|
||||
}
|
||||
|
||||
const handleGridReady = (event: GridReadyEvent<DetailRow>) => {
|
||||
gridApi.value = event.api
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await loadFromIndexedDB()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
gridApi.value?.stopEditing()
|
||||
gridApi.value = null
|
||||
void saveToIndexedDB()
|
||||
})
|
||||
const processCellForClipboard = (params: any) => {
|
||||
@ -542,6 +558,7 @@ const mydiyTheme = myTheme.withParams({
|
||||
:columnDefs="columnDefs" :gridOptions="gridOptions" :theme="mydiyTheme" :treeData="false"
|
||||
:animateRows="true"
|
||||
:enableCellSpan="true"
|
||||
@grid-ready="handleGridReady"
|
||||
@cell-value-changed="handleCellValueChanged" :suppressColumnVirtualisation="true"
|
||||
:suppressRowVirtualisation="true"
|
||||
|
||||
|
||||
@ -1,7 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onActivated, onBeforeUnmount, onDeactivated, onMounted, ref, watch } from 'vue'
|
||||
import { AgGridVue } from 'ag-grid-vue3'
|
||||
import type { ColDef, ColGroupDef, GridApi, GridReadyEvent } from 'ag-grid-community'
|
||||
import type {
|
||||
ColDef,
|
||||
ColGroupDef,
|
||||
FirstDataRenderedEvent,
|
||||
GridApi,
|
||||
GridReadyEvent,
|
||||
RowDataUpdatedEvent
|
||||
} from 'ag-grid-community'
|
||||
import { expertList } from '@/sql'
|
||||
import { myTheme, gridOptions, agGridWrapClass, agGridStyle } from '@/lib/diyAgGridOptions'
|
||||
import { decimalAggSum, roundTo, sumByNumber, toDecimal } from '@/lib/decimal'
|
||||
@ -28,7 +35,6 @@ interface DetailRow {
|
||||
interface GridState {
|
||||
detailRows: DetailRow[]
|
||||
}
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
storageKey: string
|
||||
@ -369,6 +375,7 @@ const columnDefs: (ColDef<DetailRow> | ColGroupDef<DetailRow>)[] = [
|
||||
tooltipField: 'expertName',
|
||||
wrapText: true,
|
||||
autoHeight: true,
|
||||
cellClass: 'hourly-fee-name-cell',
|
||||
cellStyle: { whiteSpace: 'normal', lineHeight: '1.2' },
|
||||
valueFormatter: params => (params.node?.rowPinned ? '' : params.value || '')
|
||||
},
|
||||
@ -465,13 +472,20 @@ const saveToIndexedDB = async () => {
|
||||
}
|
||||
|
||||
if (useServicePricingState.value && serviceMethod.value) {
|
||||
zxFwPricingStore.setServicePricingMethodState(props.contractId!, props.serviceId!, serviceMethod.value, payload)
|
||||
zxFwPricingStore.setServicePricingMethodState(
|
||||
props.contractId!,
|
||||
props.serviceId!,
|
||||
serviceMethod.value,
|
||||
payload,
|
||||
{ force: true }
|
||||
)
|
||||
} else if (useHtMethodState.value) {
|
||||
zxFwPricingStore.setHtFeeMethodState(
|
||||
props.htMainStorageKey!,
|
||||
props.htRowId!,
|
||||
props.htMethodType!,
|
||||
payload
|
||||
payload,
|
||||
{ force: true }
|
||||
)
|
||||
} else {
|
||||
zxFwPricingStore.setKeyState(props.storageKey, payload)
|
||||
@ -535,16 +549,26 @@ const handleGridReady = (event: GridReadyEvent<DetailRow>) => {
|
||||
}
|
||||
|
||||
let autoHeightSyncTimer: ReturnType<typeof setTimeout> | null = null
|
||||
const forceRefreshCellsOnLiveApi = () => {
|
||||
// 再次触发一轮强制刷新,覆盖 AG Grid 异步布局后的高度计算。
|
||||
setTimeout(() => {
|
||||
const liveApi = gridApi.value
|
||||
if (!liveApi || liveApi.isDestroyed?.()) return
|
||||
liveApi.refreshCells({ force: true })
|
||||
liveApi.redrawRows()
|
||||
}, 16)
|
||||
}
|
||||
|
||||
const syncAutoRowHeights = async () => {
|
||||
await nextTick()
|
||||
const api = gridApi.value
|
||||
if (!api) return
|
||||
if (!api || api.isDestroyed?.()) return
|
||||
api.resetRowHeights()
|
||||
api.onRowHeightChanged()
|
||||
api.refreshCells({ force: true })
|
||||
api.redrawRows()
|
||||
forceRefreshCellsOnLiveApi()
|
||||
}
|
||||
|
||||
const scheduleAutoRowHeights = () => {
|
||||
if (autoHeightSyncTimer) clearTimeout(autoHeightSyncTimer)
|
||||
autoHeightSyncTimer = setTimeout(() => {
|
||||
@ -561,6 +585,14 @@ const onColumnResized = () => {
|
||||
scheduleAutoRowHeights()
|
||||
}
|
||||
|
||||
const onFirstDataRendered = (_event: FirstDataRenderedEvent<DetailRow>) => {
|
||||
scheduleAutoRowHeights()
|
||||
}
|
||||
|
||||
const onRowDataUpdated = (_event: RowDataUpdatedEvent<DetailRow>) => {
|
||||
scheduleAutoRowHeights()
|
||||
}
|
||||
|
||||
const processCellForClipboard = (params: any) => {
|
||||
if (Array.isArray(params.value)) return JSON.stringify(params.value)
|
||||
return params.value
|
||||
@ -648,6 +680,8 @@ onBeforeUnmount(() => {
|
||||
:undoRedoCellEditing="true"
|
||||
:undoRedoCellEditingLimit="20"
|
||||
@grid-ready="handleGridReady"
|
||||
@first-data-rendered="onFirstDataRendered"
|
||||
@row-data-updated="onRowDataUpdated"
|
||||
@grid-size-changed="onGridSizeChanged"
|
||||
@column-resized="onColumnResized"
|
||||
/>
|
||||
@ -655,3 +689,18 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.hourly-fee-name-cell.ag-cell-auto-height) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
:deep(.hourly-fee-name-cell.ag-cell-auto-height .ag-cell-wrapper),
|
||||
:deep(.hourly-fee-name-cell.ag-cell-auto-height .ag-cell-value) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
white-space: normal;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -228,7 +228,8 @@ const saveToIndexedDB = async () => {
|
||||
props.htMainStorageKey!,
|
||||
props.htRowId!,
|
||||
props.htMethodType!,
|
||||
payload
|
||||
payload,
|
||||
{ force: true }
|
||||
)
|
||||
} else {
|
||||
zxFwPricingStore.setKeyState(props.storageKey, payload)
|
||||
@ -430,6 +431,7 @@ watch(
|
||||
)
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
gridApi.value?.stopEditing()
|
||||
gridApi.value = null
|
||||
void saveToIndexedDB()
|
||||
})
|
||||
|
||||
@ -664,6 +664,7 @@ watch(
|
||||
)
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
gridApi.value?.stopEditing()
|
||||
saveToStore()
|
||||
})
|
||||
const handleDeleteConfirmOpenChange = (open: boolean) => {
|
||||
@ -804,4 +805,19 @@ const confirmDeleteRow = () => {
|
||||
min-width: 0;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
:deep(.work-content-main-cell.ag-cell-auto-height),
|
||||
:deep(.remark-wrap-cell.ag-cell-auto-height) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
:deep(.work-content-main-cell.ag-cell-auto-height .ag-cell-wrapper),
|
||||
:deep(.work-content-main-cell.ag-cell-auto-height .ag-cell-value),
|
||||
:deep(.remark-wrap-cell.ag-cell-auto-height .ag-cell-wrapper),
|
||||
:deep(.remark-wrap-cell.ag-cell-auto-height .ag-cell-value) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -5,6 +5,7 @@ import type { ColDef, FirstDataRenderedEvent, GridApi, GridReadyEvent, GridSizeC
|
||||
import { myTheme, gridOptions, agGridWrapClass, agGridStyle } from '@/lib/diyAgGridOptions'
|
||||
import { parseNumberOrNull } from '@/lib/number'
|
||||
import { AG_GRID_LOCALE_CN } from '@ag-grid-community/locale'
|
||||
import { useZxFwPricingStore } from '@/pinia/zxFwPricing'
|
||||
import { useKvStore } from '@/pinia/kv'
|
||||
|
||||
interface DictItem {
|
||||
@ -42,6 +43,7 @@ const props = defineProps<{
|
||||
initBudgetValueFromStandard?: boolean
|
||||
}>()
|
||||
|
||||
const zxFwPricingStore = useZxFwPricingStore()
|
||||
const kvStore = useKvStore()
|
||||
const detailRows = ref<FactorRow[]>([])
|
||||
const gridApi = ref<GridApi<FactorRow> | null>(null)
|
||||
@ -228,7 +230,7 @@ const saveToIndexedDB = async () => {
|
||||
const payload: GridState = {
|
||||
detailRows: JSON.parse(JSON.stringify(detailRows.value))
|
||||
}
|
||||
await kvStore.setItem(props.storageKey, payload)
|
||||
zxFwPricingStore.setKeyState(props.storageKey, payload)
|
||||
} catch (error) {
|
||||
console.error('saveToIndexedDB failed:', error)
|
||||
}
|
||||
@ -236,9 +238,18 @@ const saveToIndexedDB = async () => {
|
||||
|
||||
const loadGridState = async (storageKey: string): Promise<GridState | null> => {
|
||||
if (!storageKey) return null
|
||||
const data = await kvStore.getItem<GridState>(storageKey)
|
||||
if (!data?.detailRows || !Array.isArray(data.detailRows)) return null
|
||||
return data
|
||||
const piniaData = await zxFwPricingStore.loadKeyState<GridState>(storageKey)
|
||||
if (piniaData?.detailRows && Array.isArray(piniaData.detailRows)) return piniaData
|
||||
|
||||
// 兼容历史 kvStore 数据:命中后迁移到 pinia keyed state。
|
||||
const legacyData = await kvStore.getItem<GridState>(storageKey)
|
||||
if (!legacyData?.detailRows || !Array.isArray(legacyData.detailRows)) return null
|
||||
zxFwPricingStore.setKeyState(storageKey, legacyData, { force: true })
|
||||
return legacyData
|
||||
}
|
||||
|
||||
const handleGridReady = (event: GridReadyEvent<FactorRow>) => {
|
||||
gridApi.value = event.api
|
||||
}
|
||||
|
||||
const loadFromIndexedDB = async () => {
|
||||
@ -312,6 +323,7 @@ watch(
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (gridPersistTimer) clearTimeout(gridPersistTimer)
|
||||
gridApi.value?.stopEditing()
|
||||
gridApi.value = null
|
||||
void saveToIndexedDB()
|
||||
})
|
||||
@ -348,6 +360,7 @@ onBeforeUnmount(() => {
|
||||
:processCellFromClipboard="processCellFromClipboard"
|
||||
:undoRedoCellEditing="true"
|
||||
:undoRedoCellEditingLimit="20"
|
||||
@grid-ready="handleGridReady"
|
||||
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
|
||||
import {
|
||||
CellStyleModule,
|
||||
AggregationModule,ServerSideRowModelApiModule ,UndoRedoEditModule, CellStyleModule,
|
||||
ClientSideRowModelModule,
|
||||
ColumnAutoSizeModule,
|
||||
LargeTextEditorModule,
|
||||
@ -10,11 +11,7 @@ import {
|
||||
RowAutoHeightModule,
|
||||
TextEditorModule,
|
||||
TooltipModule,ClientSideRowModelApiModule ,
|
||||
UndoRedoEditModule,RenderApiModule ,ColumnApiModule ,CellSpanModule ,RowStyleModule ,RowSelectionModule
|
||||
|
||||
} from 'ag-grid-community'
|
||||
import {
|
||||
AggregationModule,ServerSideRowModelApiModule ,
|
||||
RenderApiModule ,ColumnApiModule ,CellSpanModule ,RowStyleModule ,RowSelectionModule ,
|
||||
CellSelectionModule,
|
||||
ClipboardModule,
|
||||
LicenseManager,
|
||||
|
||||
@ -219,7 +219,14 @@ input[inputmode='numeric'] {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.ag-cell{display: flex;}
|
||||
.ag-theme-quartz .ag-cell:not(.ag-cell-auto-height) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ag-theme-quartz .ag-cell.ag-cell-auto-height {
|
||||
display: block;
|
||||
}
|
||||
.zxfw-action-group {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user