1
This commit is contained in:
parent
32fffa4f89
commit
3dce3646e1
Binary file not shown.
|
Before Width: | Height: | Size: 107 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 86 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 86 KiB |
@ -8,6 +8,8 @@ import type {
|
|||||||
GridApi,
|
GridApi,
|
||||||
GridReadyEvent,
|
GridReadyEvent,
|
||||||
ICellRendererParams,
|
ICellRendererParams,
|
||||||
|
IGroupCellRendererParams,
|
||||||
|
IRowNode,
|
||||||
ValueFormatterParams
|
ValueFormatterParams
|
||||||
} from 'ag-grid-community'
|
} from 'ag-grid-community'
|
||||||
import { AG_GRID_LOCALE_CN } from '@ag-grid-community/locale'
|
import { AG_GRID_LOCALE_CN } from '@ag-grid-community/locale'
|
||||||
@ -74,21 +76,19 @@ const groupedServiceGroups = ref<string[]>([])
|
|||||||
const syncGroupedRowsRender = async () => {
|
const syncGroupedRowsRender = async () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
const api = gridApi.value
|
const api = gridApi.value
|
||||||
if (!api) return
|
if (!api || api.isDestroyed?.()) return
|
||||||
if (isWholeProcessGroupedMode.value) {
|
if (isWholeProcessGroupedMode.value) {
|
||||||
api.expandAll()
|
api.expandAll()
|
||||||
}
|
}
|
||||||
api.refreshClientSideRowModel('group')
|
api.refreshClientSideRowModel('group')
|
||||||
api.resetRowHeights()
|
|
||||||
api.refreshCells({ force: true })
|
api.refreshCells({ force: true })
|
||||||
api.redrawRows()
|
api.redrawRows()
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const liveApi = gridApi.value
|
const liveApi = gridApi.value
|
||||||
if (!liveApi) return
|
if (!liveApi || liveApi.isDestroyed?.()) return
|
||||||
if (isWholeProcessGroupedMode.value) {
|
if (isWholeProcessGroupedMode.value) {
|
||||||
liveApi.expandAll()
|
liveApi.expandAll()
|
||||||
}
|
}
|
||||||
liveApi.resetRowHeights()
|
|
||||||
liveApi.refreshCells({ force: true })
|
liveApi.refreshCells({ force: true })
|
||||||
liveApi.redrawRows()
|
liveApi.redrawRows()
|
||||||
}, 16)
|
}, 16)
|
||||||
@ -100,6 +100,15 @@ const toServiceId = (value: unknown): number | null => {
|
|||||||
return parsed
|
return parsed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getDictRowMergeKey = (row: Pick<WorkContentRow, 'content' | 'serviceid' | 'serviceGroup'>) => {
|
||||||
|
const content = String(row.content || '').trim()
|
||||||
|
const serviceid = toServiceId(row.serviceid)
|
||||||
|
if (serviceid != null) return `sid:${serviceid}|content:${content}`
|
||||||
|
const groupName = String(row.serviceGroup || '').trim()
|
||||||
|
if (groupName) return `group:${groupName}|content:${content}`
|
||||||
|
return `content:${content}`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const loadProjectIndustryId = async () => {
|
const loadProjectIndustryId = async () => {
|
||||||
@ -156,17 +165,7 @@ const buildDefaultRowsFromDict = async (): Promise<WorkContentRow[]> => {
|
|||||||
} else {
|
} else {
|
||||||
filtered = entries.filter(e => e.serviceid === sid)
|
filtered = entries.filter(e => e.serviceid === sid)
|
||||||
}
|
}
|
||||||
console.log('[WorkContentGrid][init-group]', {
|
|
||||||
storageKey: props.storageKey,
|
|
||||||
dictMode: props.dictMode,
|
|
||||||
serviceId: sid,
|
|
||||||
industryId,
|
|
||||||
groupedBy,
|
|
||||||
matchedWholeProcessGroup,
|
|
||||||
groupedServiceIds,
|
|
||||||
groupedEnabled: isWholeProcessGroupedMode.value,
|
|
||||||
filteredCount: filtered.length
|
|
||||||
})
|
|
||||||
} else if (props.dictMode === 'additional') {
|
} else if (props.dictMode === 'additional') {
|
||||||
filtered = entries.filter(e => e.serviceid === -1 && props.storageKey.split('-').at(-1) =='2')
|
filtered = entries.filter(e => e.serviceid === -1 && props.storageKey.split('-').at(-1) =='2')
|
||||||
} else {
|
} else {
|
||||||
@ -202,7 +201,7 @@ const buildDefaultRowsFromDict = async (): Promise<WorkContentRow[]> => {
|
|||||||
serviceGroup,
|
serviceGroup,
|
||||||
serviceid: toServiceId(entry.serviceid),
|
serviceid: toServiceId(entry.serviceid),
|
||||||
remark: '',
|
remark: '',
|
||||||
checked: false,
|
checked: true,
|
||||||
custom: false,
|
custom: false,
|
||||||
path: isWholeProcessGroupedMode.value && serviceGroup
|
path: isWholeProcessGroupedMode.value && serviceGroup
|
||||||
? [serviceGroup, content]
|
? [serviceGroup, content]
|
||||||
@ -255,6 +254,7 @@ const loadFromStore = async () => {
|
|||||||
const persistedRows = state.detailRows.map(item => ({
|
const persistedRows = state.detailRows.map(item => ({
|
||||||
...item,
|
...item,
|
||||||
type: item.custom ? '自定义' : (item.type || '基本工作'),
|
type: item.custom ? '自定义' : (item.type || '基本工作'),
|
||||||
|
checked: item.custom ? false : item.checked !== false,
|
||||||
serviceid: toServiceId(item.serviceid),
|
serviceid: toServiceId(item.serviceid),
|
||||||
path: Array.isArray(item.path) && item.path.length ? item.path : ['自定义', item.content || '未命名']
|
path: Array.isArray(item.path) && item.path.length ? item.path : ['自定义', item.content || '未命名']
|
||||||
})) as WorkContentRow[]
|
})) as WorkContentRow[]
|
||||||
@ -280,16 +280,16 @@ const loadFromStore = async () => {
|
|||||||
if (defaultRows.length > 0) {
|
if (defaultRows.length > 0) {
|
||||||
const persistedCustomRows = persistedRows.filter(item => item.custom)
|
const persistedCustomRows = persistedRows.filter(item => item.custom)
|
||||||
const persistedDictRows = persistedRows.filter(item => !item.custom)
|
const persistedDictRows = persistedRows.filter(item => !item.custom)
|
||||||
const persistedByContent = new Map(
|
const persistedByKey = new Map(
|
||||||
persistedDictRows.map(item => [String(item.content || '').trim(), item])
|
persistedDictRows.map(item => [getDictRowMergeKey(item), item])
|
||||||
)
|
)
|
||||||
const mergedDictRows = defaultRows.map(item => {
|
const mergedDictRows = defaultRows.map(item => {
|
||||||
const key = String(item.content || '').trim()
|
const key = getDictRowMergeKey(item)
|
||||||
const old = persistedByContent.get(key)
|
const old = persistedByKey.get(key)
|
||||||
if (!old) return item
|
if (!old) return item
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
checked: Boolean(old.checked),
|
checked: old.checked !== false,
|
||||||
remark: String(old.remark || ''),
|
remark: String(old.remark || ''),
|
||||||
type: old.type || item.type
|
type: old.type || item.type
|
||||||
}
|
}
|
||||||
@ -318,6 +318,60 @@ const handleCheckedToggle = (id: string, checked: boolean) => {
|
|||||||
saveToStore()
|
saveToStore()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getGroupCheckableRows = (node?: IRowNode<WorkContentRow> | null) => {
|
||||||
|
if (!node) return []
|
||||||
|
return (node.allLeafChildren || [])
|
||||||
|
.map(item => item.data)
|
||||||
|
.filter((item): item is WorkContentRow => Boolean(item && !isAddTriggerRow(item) && !item.custom))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleGroupCheckedToggle = (node: IRowNode<WorkContentRow>, checked: boolean) => {
|
||||||
|
const groupRows = getGroupCheckableRows(node)
|
||||||
|
if (groupRows.length === 0) return
|
||||||
|
const targetIds = new Set(groupRows.map(item => item.id))
|
||||||
|
let changed = false
|
||||||
|
for (const row of rowData.value) {
|
||||||
|
if (!targetIds.has(row.id)) continue
|
||||||
|
if (row.checked === checked) continue
|
||||||
|
row.checked = checked
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
if (!changed) return
|
||||||
|
gridApi.value?.refreshCells({ force: true })
|
||||||
|
gridApi.value?.redrawRows()
|
||||||
|
saveToStore()
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupRowRendererParams = computed<IGroupCellRendererParams<WorkContentRow> | undefined>(() => {
|
||||||
|
if (!isWholeProcessGroupedMode.value) return undefined
|
||||||
|
return {
|
||||||
|
suppressCount: true,
|
||||||
|
innerRenderer: (params: ICellRendererParams<WorkContentRow>) => {
|
||||||
|
const wrapper = document.createElement('div')
|
||||||
|
wrapper.className = 'work-content-group-row'
|
||||||
|
const checkbox = document.createElement('input')
|
||||||
|
checkbox.type = 'checkbox'
|
||||||
|
checkbox.className = 'work-content-group-check'
|
||||||
|
const rows = getGroupCheckableRows(params.node)
|
||||||
|
const checkedCount = rows.filter(item => item.checked).length
|
||||||
|
checkbox.checked = rows.length > 0 && checkedCount === rows.length
|
||||||
|
checkbox.indeterminate = checkedCount > 0 && checkedCount < rows.length
|
||||||
|
checkbox.disabled = rows.length === 0
|
||||||
|
checkbox.addEventListener('mousedown', event => event.stopPropagation())
|
||||||
|
checkbox.addEventListener('click', event => event.stopPropagation())
|
||||||
|
checkbox.addEventListener('change', event => {
|
||||||
|
event.stopPropagation()
|
||||||
|
handleGroupCheckedToggle(params.node, checkbox.checked)
|
||||||
|
})
|
||||||
|
const label = document.createElement('span')
|
||||||
|
label.className = 'work-content-group-label'
|
||||||
|
label.textContent = String(params.valueFormatted || params.value || params.node.key || '')
|
||||||
|
wrapper.append(checkbox, label)
|
||||||
|
return wrapper
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const contentCellRenderer = (params: ICellRendererParams<WorkContentRow>) => {
|
const contentCellRenderer = (params: ICellRendererParams<WorkContentRow>) => {
|
||||||
const data = params.data
|
const data = params.data
|
||||||
if (!data) return ''
|
if (!data) return ''
|
||||||
@ -649,7 +703,7 @@ const confirmDeleteRow = () => {
|
|||||||
:getDataPath="getDataPath"
|
:getDataPath="getDataPath"
|
||||||
:groupDefaultExpanded="isWholeProcessGroupedMode ? -1 : 0"
|
:groupDefaultExpanded="isWholeProcessGroupedMode ? -1 : 0"
|
||||||
:groupDisplayType="isWholeProcessGroupedMode ? 'groupRows' : undefined"
|
:groupDisplayType="isWholeProcessGroupedMode ? 'groupRows' : undefined"
|
||||||
:groupRowRendererParams="isWholeProcessGroupedMode ? { suppressCount: true } : undefined"
|
:groupRowRendererParams="groupRowRendererParams"
|
||||||
:animateRows="true"
|
:animateRows="true"
|
||||||
:localeText="AG_GRID_LOCALE_CN"
|
:localeText="AG_GRID_LOCALE_CN"
|
||||||
:tooltipShowDelay="500"
|
:tooltipShowDelay="500"
|
||||||
@ -728,4 +782,26 @@ const confirmDeleteRow = () => {
|
|||||||
height: 14px;
|
height: 14px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(.work-content-group-row) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.work-content-group-check) {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.work-content-group-check:disabled) {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.work-content-group-label) {
|
||||||
|
min-width: 0;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -615,7 +615,7 @@ onMounted(() => {
|
|||||||
class="text-sm font-semibold text-foreground cursor-pointer select-none transition-colors hover:text-primary">
|
class="text-sm font-semibold text-foreground cursor-pointer select-none transition-colors hover:text-primary">
|
||||||
{{ props.title }}
|
{{ props.title }}
|
||||||
</h3>
|
</h3>
|
||||||
<div class="flex items-center gap-2">
|
<!-- <div class="flex items-center gap-2">
|
||||||
<span class=" text-xs text-muted-foreground">简要计算</span>
|
<span class=" text-xs text-muted-foreground">简要计算</span>
|
||||||
<SwitchRoot
|
<SwitchRoot
|
||||||
class="cursor-pointer peer h-5 w-9 shrink-0 rounded-full border border-transparent bg-muted shadow-sm transition-colors data-[state=checked]:bg-primary"
|
class="cursor-pointer peer h-5 w-9 shrink-0 rounded-full border border-transparent bg-muted shadow-sm transition-colors data-[state=checked]:bg-primary"
|
||||||
@ -623,7 +623,7 @@ onMounted(() => {
|
|||||||
<SwitchThumb
|
<SwitchThumb
|
||||||
class="block h-4 w-4 translate-x-0.5 rounded-full bg-background shadow transition-transform data-[state=checked]:translate-x-4" />
|
class="block h-4 w-4 translate-x-0.5 rounded-full bg-background shadow transition-transform data-[state=checked]:translate-x-4" />
|
||||||
</SwitchRoot>
|
</SwitchRoot>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div :class="agGridWrapClass">
|
<div :class="agGridWrapClass">
|
||||||
|
|||||||
@ -620,6 +620,7 @@ export const useZxFwPricingStore = defineStore('zxFwPricing', () => {
|
|||||||
if (!targetServiceId) return false
|
if (!targetServiceId) return false
|
||||||
|
|
||||||
const nextValue = toFiniteNumberOrNull(params.value)
|
const nextValue = toFiniteNumberOrNull(params.value)
|
||||||
|
|
||||||
let changed = false
|
let changed = false
|
||||||
const updatedRows = current.detailRows.map(row => {
|
const updatedRows = current.detailRows.map(row => {
|
||||||
if (String(row.id || '') !== targetServiceId) return row
|
if (String(row.id || '') !== targetServiceId) return row
|
||||||
@ -674,6 +675,8 @@ export const useZxFwPricingStore = defineStore('zxFwPricing', () => {
|
|||||||
if (isSameState(current, nextState)) return false
|
if (isSameState(current, nextState)) return false
|
||||||
contracts.value[contractId] = nextState
|
contracts.value[contractId] = nextState
|
||||||
contractLoaded.value[contractId] = true
|
contractLoaded.value[contractId] = true
|
||||||
|
const targetRow = nextState.detailRows.find(row => String(row.id || '') === targetServiceId)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user