WIP
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import type { ConstructeurLinkEntry } from '~/shared/constructeurUtils'
|
||||
import { extractCollection } from '~/shared/utils/apiHelpers'
|
||||
|
||||
type EntityType = 'machine' | 'piece' | 'composant' | 'product'
|
||||
|
||||
@@ -25,7 +26,7 @@ const ENTITY_PLURALS: Record<EntityType, string> = {
|
||||
}
|
||||
|
||||
export function useConstructeurLinks() {
|
||||
const { get, post, patch, del } = useApi()
|
||||
const { get, post, patch, delete: del } = useApi()
|
||||
|
||||
const fetchLinks = async (
|
||||
entityType: EntityType,
|
||||
@@ -34,11 +35,11 @@ export function useConstructeurLinks() {
|
||||
const endpoint = ENDPOINTS[entityType]
|
||||
const key = ENTITY_KEYS[entityType]
|
||||
const plural = ENTITY_PLURALS[entityType]
|
||||
const result = await get(`${endpoint}?${key}=/api/${plural}/${entityId}`)
|
||||
const url = `${endpoint}?${key}=/api/${plural}/${entityId}`
|
||||
const result = await get(url)
|
||||
if (!result.success || !result.data) return []
|
||||
|
||||
const data = result.data as Record<string, any>
|
||||
const members = data['hydra:member'] ?? (Array.isArray(data) ? data : [])
|
||||
const members = extractCollection(result.data)
|
||||
if (!Array.isArray(members)) return []
|
||||
|
||||
return members.map((link: any) => ({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ref, computed, type Ref, type ComputedRef } from 'vue'
|
||||
import { ref, computed, watch, type Ref, type ComputedRef } from 'vue'
|
||||
import { useUrlState } from './useUrlState'
|
||||
import type { DataTableSort, DataTablePagination, DataTableColumnFilters, SortDirection } from '~/shared/types/dataTable'
|
||||
|
||||
@@ -22,6 +22,8 @@ export interface UseDataTableOptions {
|
||||
persistToUrl?: boolean
|
||||
/** Extra URL state params for page-specific filters */
|
||||
extraParams?: Record<string, { default: string | number; type?: 'string' | 'number' }>
|
||||
/** Column filter keys to persist in URL (prefixed with `f.` in query string) */
|
||||
columnFilterKeys?: string[]
|
||||
}
|
||||
|
||||
export interface UseDataTableReturn {
|
||||
@@ -56,6 +58,7 @@ export function useDataTable(
|
||||
searchDebounceMs = 300,
|
||||
persistToUrl = true,
|
||||
extraParams = {},
|
||||
columnFilterKeys = [],
|
||||
} = options
|
||||
|
||||
let searchTerm: Ref<string>
|
||||
@@ -64,6 +67,7 @@ export function useDataTable(
|
||||
let currentPage: Ref<number>
|
||||
let itemsPerPage: Ref<number>
|
||||
const filters: Record<string, Ref<string | number>> = {}
|
||||
const columnFilterRefs: Record<string, Ref<string>> = {}
|
||||
|
||||
if (persistToUrl) {
|
||||
const paramDefs: Record<string, { default: string | number; type?: 'string' | 'number'; debounce?: number }> = {
|
||||
@@ -75,6 +79,10 @@ export function useDataTable(
|
||||
...extraParams,
|
||||
}
|
||||
|
||||
for (const key of columnFilterKeys) {
|
||||
paramDefs[`f.${key}`] = { default: '', debounce: 300 }
|
||||
}
|
||||
|
||||
const state = useUrlState(paramDefs, {
|
||||
onRestore: () => deps.fetchData(),
|
||||
})
|
||||
@@ -88,6 +96,10 @@ export function useDataTable(
|
||||
for (const key of Object.keys(extraParams)) {
|
||||
filters[key] = (state as Record<string, Ref<string | number>>)[key]!
|
||||
}
|
||||
|
||||
for (const key of columnFilterKeys) {
|
||||
columnFilterRefs[key] = (state as Record<string, Ref<string>>)[`f.${key}`]!
|
||||
}
|
||||
}
|
||||
else {
|
||||
searchTerm = ref('')
|
||||
@@ -137,8 +149,31 @@ export function useDataTable(
|
||||
deps.fetchData()
|
||||
}
|
||||
|
||||
// Column filters
|
||||
const columnFilters = ref<DataTableColumnFilters>({})
|
||||
// Column filters — seed from URL-persisted refs
|
||||
const initialColumnFilters: DataTableColumnFilters = {}
|
||||
for (const [key, r] of Object.entries(columnFilterRefs)) {
|
||||
if (r.value) initialColumnFilters[key] = r.value
|
||||
}
|
||||
const columnFilters = ref<DataTableColumnFilters>(initialColumnFilters)
|
||||
|
||||
// Sync columnFilters → URL refs
|
||||
if (persistToUrl && columnFilterKeys.length > 0) {
|
||||
watch(columnFilters, (val) => {
|
||||
for (const key of columnFilterKeys) {
|
||||
columnFilterRefs[key]!.value = val[key] || ''
|
||||
}
|
||||
}, { deep: true })
|
||||
|
||||
// Sync URL refs → columnFilters (back/forward navigation)
|
||||
for (const key of columnFilterKeys) {
|
||||
watch(columnFilterRefs[key]!, (urlVal) => {
|
||||
const current = columnFilters.value[key] || ''
|
||||
if (current !== urlVal) {
|
||||
columnFilters.value = { ...columnFilters.value, [key]: urlVal }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleColumnFiltersChange = (newFilters: DataTableColumnFilters) => {
|
||||
columnFilters.value = newFilters
|
||||
|
||||
@@ -21,7 +21,11 @@ import {
|
||||
resolveConstructeurs,
|
||||
uniqueConstructeurIds,
|
||||
formatConstructeurContact as formatConstructeurContactSummary,
|
||||
parseConstructeurLinksFromApi,
|
||||
constructeurIdsFromLinks,
|
||||
} from '~/shared/constructeurUtils'
|
||||
import type { ConstructeurLinkEntry } from '~/shared/constructeurUtils'
|
||||
import { useConstructeurLinks } from '~/composables/useConstructeurLinks'
|
||||
import { useMachineDetailDocuments } from '~/composables/useMachineDetailDocuments'
|
||||
import { useMachineDetailCustomFields } from '~/composables/useMachineDetailCustomFields'
|
||||
import { useMachineDetailHierarchy } from '~/composables/useMachineDetailHierarchy'
|
||||
@@ -64,6 +68,11 @@ export function useMachineDetailData(machineId: string) {
|
||||
const printAreaRef = ref<HTMLElement | null>(null)
|
||||
const saving = ref(false)
|
||||
|
||||
// Constructeur links
|
||||
const { fetchLinks, syncLinks } = useConstructeurLinks()
|
||||
const constructeurLinks = ref<ConstructeurLinkEntry[]>([])
|
||||
const originalConstructeurLinks = ref<ConstructeurLinkEntry[]>([])
|
||||
|
||||
// Machine fields
|
||||
const machineName = ref('')
|
||||
const machineReference = ref('')
|
||||
@@ -78,20 +87,15 @@ export function useMachineDetailData(machineId: string) {
|
||||
})
|
||||
|
||||
const machineConstructeursDisplay = computed(() => {
|
||||
const ids = uniqueConstructeurIds(
|
||||
machineConstructeurIds.value,
|
||||
(machine.value as AnyRecord)?.constructeurIds,
|
||||
(machine.value as AnyRecord)?.constructeurs,
|
||||
(machine.value as AnyRecord)?.constructeur,
|
||||
)
|
||||
const ids = machineConstructeurIds.value
|
||||
if (!ids.length) return [] as any[]
|
||||
// Extract nested constructeur objects from link entries as candidate pool
|
||||
const linkConstructeurs = constructeurLinks.value
|
||||
.filter(l => l.constructeur && l.constructeur.id)
|
||||
.map(l => l.constructeur!) as any[]
|
||||
return resolveConstructeurs(
|
||||
ids,
|
||||
Array.isArray((machine.value as AnyRecord)?.constructeurs)
|
||||
? ((machine.value as AnyRecord).constructeurs as any[])
|
||||
: [],
|
||||
(machine.value as AnyRecord)?.constructeur
|
||||
? [(machine.value as AnyRecord).constructeur as any]
|
||||
: [],
|
||||
linkConstructeurs,
|
||||
constructeurs.value as any,
|
||||
) as any[]
|
||||
})
|
||||
@@ -235,11 +239,12 @@ export function useMachineDetailData(machineId: string) {
|
||||
if (machine.value) {
|
||||
machineName.value = (machine.value.name as string) || ''
|
||||
machineReference.value = (machine.value.reference as string) || ''
|
||||
machineConstructeurIds.value = uniqueConstructeurIds(
|
||||
machine.value.constructeurIds,
|
||||
machine.value.constructeurs,
|
||||
machine.value.constructeur,
|
||||
)
|
||||
// Parse constructeur links from structure response
|
||||
const rawLinks = Array.isArray(machine.value.constructeurs) ? machine.value.constructeurs as any[] : []
|
||||
const parsed = parseConstructeurLinksFromApi(rawLinks)
|
||||
constructeurLinks.value = parsed
|
||||
originalConstructeurLinks.value = parsed.map(l => ({ ...l }))
|
||||
machineConstructeurIds.value = constructeurIdsFromLinks(parsed)
|
||||
machineSiteId.value = (machine.value.siteId as string) || (machine.value.site as AnyRecord)?.id as string || ''
|
||||
}
|
||||
}
|
||||
@@ -269,6 +274,8 @@ export function useMachineDetailData(machineId: string) {
|
||||
machineReference,
|
||||
machineSiteId,
|
||||
machineConstructeurIds,
|
||||
constructeurLinks,
|
||||
originalConstructeurLinks,
|
||||
machineDocumentsLoaded,
|
||||
machineComponentLinks,
|
||||
machinePieceLinks,
|
||||
@@ -284,6 +291,7 @@ export function useMachineDetailData(machineId: string) {
|
||||
updatePieceApi,
|
||||
apiPatch,
|
||||
toast,
|
||||
syncLinks,
|
||||
})
|
||||
|
||||
// UI methods
|
||||
@@ -338,6 +346,8 @@ export function useMachineDetailData(machineId: string) {
|
||||
const cancelEdition = () => {
|
||||
initMachineFields()
|
||||
syncMachineCustomFields()
|
||||
constructeurLinks.value = originalConstructeurLinks.value.map(l => ({ ...l }))
|
||||
machineConstructeurIds.value = constructeurIdsFromLinks(constructeurLinks.value)
|
||||
isEditMode.value = false
|
||||
}
|
||||
|
||||
@@ -467,6 +477,7 @@ export function useMachineDetailData(machineId: string) {
|
||||
// Machine fields
|
||||
machineName, machineReference, machineSiteId, machineConstructeurIds, machineConstructeurId,
|
||||
machineConstructeursDisplay, machineConstructeurContact, hasMachineConstructeur,
|
||||
constructeurLinks, originalConstructeurLinks,
|
||||
sites,
|
||||
|
||||
// UI state
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
*/
|
||||
|
||||
import type { Ref } from 'vue'
|
||||
import { uniqueConstructeurIds } from '~/shared/constructeurUtils'
|
||||
import { uniqueConstructeurIds, constructeurIdsFromLinks } from '~/shared/constructeurUtils'
|
||||
import type { ConstructeurLinkEntry } from '~/shared/constructeurUtils'
|
||||
|
||||
type AnyRecord = Record<string, unknown>
|
||||
|
||||
@@ -15,6 +16,8 @@ export interface UseMachineDetailUpdatesDeps {
|
||||
machineReference: Ref<string>
|
||||
machineSiteId: Ref<string>
|
||||
machineConstructeurIds: Ref<string[]>
|
||||
constructeurLinks: Ref<ConstructeurLinkEntry[]>
|
||||
originalConstructeurLinks: Ref<ConstructeurLinkEntry[]>
|
||||
machineDocumentsLoaded: Ref<boolean>
|
||||
machineComponentLinks: Ref<AnyRecord[]>
|
||||
machinePieceLinks: Ref<AnyRecord[]>
|
||||
@@ -35,6 +38,12 @@ export interface UseMachineDetailUpdatesDeps {
|
||||
updatePieceApi: (id: string, data: any) => Promise<unknown>
|
||||
apiPatch: (endpoint: string, data?: unknown) => Promise<any>
|
||||
toast: { showInfo: (msg: string) => void }
|
||||
syncLinks: (
|
||||
entityType: 'machine' | 'piece' | 'composant' | 'product',
|
||||
entityId: string,
|
||||
originalLinks: ConstructeurLinkEntry[],
|
||||
formLinks: ConstructeurLinkEntry[],
|
||||
) => Promise<void>
|
||||
}
|
||||
|
||||
export function useMachineDetailUpdates(deps: UseMachineDetailUpdatesDeps) {
|
||||
@@ -44,6 +53,8 @@ export function useMachineDetailUpdates(deps: UseMachineDetailUpdatesDeps) {
|
||||
machineReference,
|
||||
machineSiteId,
|
||||
machineConstructeurIds,
|
||||
constructeurLinks,
|
||||
originalConstructeurLinks,
|
||||
machineComponentLinks,
|
||||
machinePieceLinks,
|
||||
applyMachineLinks,
|
||||
@@ -56,19 +67,16 @@ export function useMachineDetailUpdates(deps: UseMachineDetailUpdatesDeps) {
|
||||
updatePieceApi,
|
||||
apiPatch,
|
||||
toast,
|
||||
syncLinks,
|
||||
} = deps
|
||||
|
||||
const updateMachineInfo = async () => {
|
||||
if (!machine.value) return
|
||||
try {
|
||||
const cIds = uniqueConstructeurIds(machineConstructeurIds.value)
|
||||
machineConstructeurIds.value = cIds
|
||||
|
||||
const result: any = await updateMachineApi(machine.value.id as string, {
|
||||
name: machineName.value,
|
||||
reference: machineReference.value,
|
||||
siteId: machineSiteId.value || undefined,
|
||||
constructeurIds: cIds,
|
||||
} as any)
|
||||
if (result.success) {
|
||||
const machinePayload =
|
||||
@@ -82,11 +90,6 @@ export function useMachineDetailUpdates(deps: UseMachineDetailUpdatesDeps) {
|
||||
documents: machinePayload.documents || machine.value.documents || [],
|
||||
customFieldValues: machinePayload.customFieldValues || machine.value.customFieldValues || [],
|
||||
}
|
||||
machineConstructeurIds.value = uniqueConstructeurIds(
|
||||
machine.value!.constructeurIds,
|
||||
machine.value!.constructeurs,
|
||||
machine.value!.constructeur,
|
||||
)
|
||||
const linksApplied = applyMachineLinks(result.data)
|
||||
if (linksApplied && machine.value) {
|
||||
machine.value.componentLinks = machineComponentLinks.value
|
||||
@@ -95,6 +98,9 @@ export function useMachineDetailUpdates(deps: UseMachineDetailUpdatesDeps) {
|
||||
loadProductDocuments().catch(() => {})
|
||||
}
|
||||
}
|
||||
// Sync constructeur links after entity save
|
||||
await syncLinks('machine', machine.value!.id as string, originalConstructeurLinks.value, constructeurLinks.value)
|
||||
originalConstructeurLinks.value = constructeurLinks.value.map(l => ({ ...l }))
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour de la machine:', error)
|
||||
}
|
||||
@@ -209,7 +215,13 @@ export function useMachineDetailUpdates(deps: UseMachineDetailUpdatesDeps) {
|
||||
}
|
||||
|
||||
const handleMachineConstructeurChange = (value: unknown) => {
|
||||
machineConstructeurIds.value = uniqueConstructeurIds(value)
|
||||
const newIds = uniqueConstructeurIds(value)
|
||||
machineConstructeurIds.value = newIds
|
||||
// Sync constructeurLinks: keep existing entries, add new ones
|
||||
const existingMap = new Map(constructeurLinks.value.map(l => [l.constructeurId, l]))
|
||||
constructeurLinks.value = newIds.map(id =>
|
||||
existingMap.get(id) ?? { constructeurId: id, supplierReference: null },
|
||||
)
|
||||
}
|
||||
|
||||
const editComponent = () => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { ref } from 'vue'
|
||||
import { useToast } from './useToast'
|
||||
import { useApi, type ApiResponse } from './useApi'
|
||||
import { buildConstructeurRequestPayload } from '~/shared/constructeurUtils'
|
||||
import { extractRelationId, normalizeRelationIds } from '~/shared/apiRelations'
|
||||
import { extractCollection } from '~/shared/utils/apiHelpers'
|
||||
|
||||
@@ -92,7 +91,7 @@ export function useMachines() {
|
||||
const createMachine = async (machineData: Partial<Machine>): Promise<ApiResponse> => {
|
||||
loading.value = true
|
||||
try {
|
||||
const normalizedPayload = normalizeRelationIds(buildConstructeurRequestPayload(machineData))
|
||||
const normalizedPayload = normalizeRelationIds(machineData as Record<string, unknown>)
|
||||
const result = await post('/machines', normalizedPayload)
|
||||
if (result.success) {
|
||||
const createdMachine = normalizeMachineResponse(result.data) ||
|
||||
@@ -116,7 +115,7 @@ export function useMachines() {
|
||||
const updateMachineData = async (id: string, machineData: Partial<Machine>): Promise<ApiResponse> => {
|
||||
loading.value = true
|
||||
try {
|
||||
const normalizedPayload = normalizeRelationIds(buildConstructeurRequestPayload(machineData))
|
||||
const normalizedPayload = normalizeRelationIds(machineData as Record<string, unknown>)
|
||||
const result = await patch(`/machines/${id}`, normalizedPayload)
|
||||
if (result.success) {
|
||||
const updatedMachine = normalizeMachineResponse(result.data) ||
|
||||
|
||||
Reference in New Issue
Block a user