From be2662d5795c0f8882e3f9badf77b922e5ebb3d9 Mon Sep 17 00:00:00 2001 From: wintsa <770775984@qq.com> Date: Thu, 26 Mar 2026 14:54:26 +0800 Subject: [PATCH] 1 --- src/features/ht/components/zxFw.vue | 87 +++++++++++--- .../components/InvestmentScalePricingPane.vue | 43 ++++++- .../components/LandScalePricingPane.vue | 43 ++++++- .../shared/components/WorkContentGrid.vue | 1 + .../shared/components/XmFactorGrid.vue | 3 + src/i18n/locales/en-US.ts | 1 + src/i18n/locales/zh-CN.ts | 1 + src/layout/tab.vue | 112 ++++++++++++++++-- src/lib/agGridReadonlyAutoHeight.ts | 112 +++++++++++++++++- src/lib/diyAgGridOptions.ts | 37 +++++- src/lib/pricingScaleColumns.ts | 6 + src/lib/pricingScaleGrid.ts | 66 +++++++++++ src/pinia/zxFwPricing.ts | 3 + src/style.css | 13 ++ 14 files changed, 493 insertions(+), 35 deletions(-) diff --git a/src/features/ht/components/zxFw.vue b/src/features/ht/components/zxFw.vue index 30a99f8..1869064 100644 --- a/src/features/ht/components/zxFw.vue +++ b/src/features/ht/components/zxFw.vue @@ -56,6 +56,7 @@ interface DetailRow { hourly: number | null subtotal?: number | null finalFee?: number | null + remark?: string actions?: unknown } @@ -180,6 +181,7 @@ const normalizeDetailRow = (row: Partial): DetailRow => ({ hourly: typeof row.hourly === 'number' ? row.hourly : null, subtotal: typeof row.subtotal === 'number' ? row.subtotal : null, finalFee: typeof row.finalFee === 'number' ? row.finalFee : null, + remark: String(row.remark || ''), actions: row.actions }) @@ -408,11 +410,11 @@ const createMethodColumn = ( ): ColDef => ({ headerName, field, - headerClass: 'ag-right-aligned-header', minWidth, flex: 1.5, editable: false, cellClassRules: { + 'zxfw-number-cell': () => true, 'ag-right-aligned-cell': () => true }, valueGetter: params => { @@ -666,11 +668,11 @@ const columnDefs: ColDef[] = [ { headerName: t('htZxFw.columns.subtotal'), field: 'subtotal', - headerClass: 'ag-right-aligned-header', flex: 2, minWidth: 100, editable: false, cellClassRules: { + 'zxfw-number-cell': () => true, 'ag-right-aligned-cell': () => true }, valueGetter: params => { @@ -682,12 +684,12 @@ const columnDefs: ColDef[] = [ { headerName: t('htZxFw.columns.finalFee'), field: 'finalFee', - headerClass: 'ag-right-aligned-header', headerTooltip: t('htZxFw.columns.finalFeeTooltip'), flex: 2, minWidth: 110, editable: params => !isFixedRow(params.data), cellClassRules: { + 'zxfw-number-cell': () => true, 'ag-right-aligned-cell': () => true }, valueGetter: params => { @@ -707,6 +709,32 @@ const columnDefs: ColDef[] = [ }, valueFormatter: params => (params.value == null ? '' : formatThousands(params.value, 2)) }, + { + headerName: t('htZxFw.columns.remark'), + field: 'remark', + minWidth: 160, + flex: 1.8, + editable: params => !isFixedRow(params.data), + cellEditor: 'agLargeTextCellEditor', + cellEditorPopup: true, + cellEditorParams: { + maxLength: 500, + rows: 8, + cols: 48 + }, + wrapText: true, + autoHeight: true, + cellStyle: { whiteSpace: 'normal', lineHeight: '1.4' }, + valueGetter: params => { + if (!params.data || isFixedRow(params.data)) return '' + return String(params.data.remark || '') + }, + valueFormatter: params => (params.value == null ? '' : String(params.value)), + cellClass: params => (!isFixedRow(params.data) ? 'remark-wrap-cell' : ''), + cellClassRules: { + 'editable-cell-empty': params => !isFixedRow(params.data) && (params.value == null || String(params.value).trim() === '') + } + }, { headerName: t('htZxFw.columns.actions'), field: 'actions', @@ -931,7 +959,8 @@ const applySelection = async (codes: string[]) => { hourly: nextValues.hourly, subtotal: typeof old?.subtotal === 'number' ? old.subtotal : null, - finalFee: typeof old?.finalFee === 'number' ? old.finalFee : null + finalFee: typeof old?.finalFee === 'number' ? old.finalFee : null, + remark: String(old?.remark || '') } }) .filter((row): row is DetailRow => row !== null) @@ -951,6 +980,7 @@ const applySelection = async (codes: string[]) => { hourly: typeof fixedOld?.hourly === 'number' ? fixedOld.hourly : null, subtotal: typeof fixedOld?.subtotal === 'number' ? fixedOld.subtotal : null, finalFee: typeof fixedOld?.finalFee === 'number' ? fixedOld.finalFee : null, + remark: '', actions: null } @@ -1000,9 +1030,9 @@ const initializeContractState = async () => { } } catch (error) { console.error('initializeContractState failed:', error) - await setCurrentContractState({ - selectedIds: [], - detailRows: applyFixedRowTotals([{ + await setCurrentContractState({ + selectedIds: [], + detailRows: applyFixedRowTotals([{ id: fixedBudgetRow.id, code: fixedBudgetRow.code, name: fixedBudgetRow.name, @@ -1011,11 +1041,12 @@ const initializeContractState = async () => { landScale: null, workload: null, hourly: null, - subtotal: null, - finalFee: null, - actions: null - }]) - }) + subtotal: null, + finalFee: null, + remark: '', + actions: null + }]) + }) } } @@ -1197,15 +1228,20 @@ const commitFinalFeeGridChanges = async () => { const handleCellValueChanged = async (event: any) => { if (isBulkClipboardMutation) return - if (event.colDef?.field !== 'finalFee') return const row = event.data as DetailRow | undefined if (!row || isFixedRow(row)) return - const newValue = event.newValue != null ? roundTo(Number(event.newValue), 2) : null + const field = String(event.colDef?.field || '') + if (field !== 'finalFee' && field !== 'remark') return const currentState = getCurrentContractState() - - const nextRows = currentState.detailRows.map(item => - item.id === row.id ? { ...item, finalFee: newValue } : item - ) + + const nextRows = currentState.detailRows.map(item => { + if (item.id !== row.id) return item + if (field === 'remark') { + return { ...item, remark: String(event.newValue || '') } + } + const newValue = event.newValue != null ? roundTo(Number(event.newValue), 2) : null + return { ...item, finalFee: newValue } + }) const finalRows = applyFixedRowSummary(nextRows) await setCurrentContractState({ ...currentState, @@ -1256,7 +1292,7 @@ onActivated(async () => { -

{{ t('htZxFw.warning') }}

+

{{ t('htZxFw.warning') }}

@@ -1319,6 +1355,14 @@ onActivated(async () => {