refactor(custom-fields) : unify 3 parallel implementations into 1 module
Replace ~2900 lines across 9 files with ~400 lines in 2 files: - shared/utils/customFields.ts (types + pure helpers) - composables/useCustomFieldInputs.ts (reactive composable) Migrated all consumers: - Backend: add defaultValue to API Platform serialization groups - Standalone pages: component edit/create, piece edit/create, product edit/create/detail - Machine page: MachineCustomFieldsCard, MachineInfoCard, useMachineDetailCustomFields - Hierarchy: ComponentItem, PieceItem - Shared: CustomFieldDisplay, CustomFieldInputGrid - Category editor: componentStructure.ts Deleted: - entityCustomFieldLogic.ts (335 lines) - customFieldUtils.ts (440 lines) - customFieldFormUtils.ts (404 lines) - useEntityCustomFields.ts (181 lines) - customFieldFormUtils.test.ts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,15 +9,15 @@
|
||||
<div :class="layoutClass">
|
||||
<div
|
||||
v-for="(field, index) in fields"
|
||||
:key="resolveFieldKey(field, index)"
|
||||
:key="fieldKey(field, index)"
|
||||
class="form-control"
|
||||
>
|
||||
<label class="label">
|
||||
<span class="label-text text-sm">{{
|
||||
resolveFieldName(field)
|
||||
field.name
|
||||
}}</span>
|
||||
<span
|
||||
v-if="resolveFieldRequired(field)"
|
||||
v-if="field.required"
|
||||
class="label-text-alt text-error"
|
||||
>*</span>
|
||||
</label>
|
||||
@@ -26,32 +26,32 @@
|
||||
<template v-if="isFieldEditable(field)">
|
||||
<!-- Champ de type TEXT -->
|
||||
<input
|
||||
v-if="resolveFieldType(field) === 'text'"
|
||||
v-if="field.type === 'text'"
|
||||
:value="field.value ?? ''"
|
||||
type="text"
|
||||
class="input input-bordered input-sm"
|
||||
:required="resolveFieldRequired(field)"
|
||||
:required="field.required"
|
||||
@input="onInput(field, ($event.target as HTMLInputElement).value)"
|
||||
@blur="onBlur(field)"
|
||||
>
|
||||
|
||||
<!-- Champ de type NUMBER -->
|
||||
<input
|
||||
v-else-if="resolveFieldType(field) === 'number'"
|
||||
v-else-if="field.type === 'number'"
|
||||
:value="field.value ?? ''"
|
||||
type="number"
|
||||
class="input input-bordered input-sm"
|
||||
:required="resolveFieldRequired(field)"
|
||||
:required="field.required"
|
||||
@input="onInput(field, ($event.target as HTMLInputElement).value)"
|
||||
@blur="onBlur(field)"
|
||||
>
|
||||
|
||||
<!-- Champ de type SELECT -->
|
||||
<select
|
||||
v-else-if="resolveFieldType(field) === 'select'"
|
||||
v-else-if="field.type === 'select'"
|
||||
:value="field.value ?? ''"
|
||||
class="select select-bordered select-sm"
|
||||
:required="resolveFieldRequired(field)"
|
||||
:required="field.required"
|
||||
@change="onInput(field, ($event.target as HTMLSelectElement).value)"
|
||||
@blur="onBlur(field)"
|
||||
>
|
||||
@@ -59,7 +59,7 @@
|
||||
Sélectionner...
|
||||
</option>
|
||||
<option
|
||||
v-for="option in resolveFieldOptions(field)"
|
||||
v-for="option in field.options"
|
||||
:key="option"
|
||||
:value="option"
|
||||
>
|
||||
@@ -69,7 +69,7 @@
|
||||
|
||||
<!-- Champ de type BOOLEAN -->
|
||||
<div
|
||||
v-else-if="resolveFieldType(field) === 'boolean'"
|
||||
v-else-if="field.type === 'boolean'"
|
||||
class="flex items-center gap-2"
|
||||
>
|
||||
<input
|
||||
@@ -85,21 +85,21 @@
|
||||
|
||||
<!-- Champ de type DATE -->
|
||||
<input
|
||||
v-else-if="resolveFieldType(field) === 'date'"
|
||||
v-else-if="field.type === 'date'"
|
||||
:value="field.value ?? ''"
|
||||
type="date"
|
||||
class="input input-bordered input-sm"
|
||||
:required="resolveFieldRequired(field)"
|
||||
:required="field.required"
|
||||
@input="onInput(field, ($event.target as HTMLInputElement).value)"
|
||||
@blur="onBlur(field)"
|
||||
>
|
||||
|
||||
<!-- Champ de type TEXTAREA -->
|
||||
<textarea
|
||||
v-else-if="resolveFieldType(field) === 'textarea'"
|
||||
v-else-if="field.type === 'textarea'"
|
||||
:value="field.value ?? ''"
|
||||
class="textarea textarea-bordered textarea-sm"
|
||||
:required="resolveFieldRequired(field)"
|
||||
:required="field.required"
|
||||
@input="onInput(field, ($event.target as HTMLTextAreaElement).value)"
|
||||
@blur="onBlur(field)"
|
||||
/>
|
||||
@@ -110,7 +110,7 @@
|
||||
:value="field.value ?? ''"
|
||||
type="text"
|
||||
class="input input-bordered input-sm"
|
||||
:required="resolveFieldRequired(field)"
|
||||
:required="field.required"
|
||||
@input="onInput(field, ($event.target as HTMLInputElement).value)"
|
||||
@blur="onBlur(field)"
|
||||
>
|
||||
@@ -119,7 +119,7 @@
|
||||
<!-- Mode lecture seule -->
|
||||
<template v-else>
|
||||
<div class="input input-bordered input-sm bg-base-200">
|
||||
{{ formatFieldDisplayValue(field) }}
|
||||
{{ formatValueForDisplay(field) }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -128,18 +128,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
resolveFieldKey,
|
||||
resolveFieldName,
|
||||
resolveFieldType,
|
||||
resolveFieldOptions,
|
||||
resolveFieldRequired,
|
||||
resolveFieldReadOnly,
|
||||
formatFieldDisplayValue,
|
||||
} from '~/shared/utils/entityCustomFieldLogic'
|
||||
import { fieldKey, formatValueForDisplay, type CustomFieldInput } from '~/shared/utils/customFields'
|
||||
|
||||
const props = defineProps<{
|
||||
fields: any[]
|
||||
fields: CustomFieldInput[]
|
||||
isEditMode: boolean
|
||||
columns?: 1 | 2
|
||||
title?: string
|
||||
@@ -150,8 +142,8 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'field-input': [field: any, value: string]
|
||||
'field-blur': [field: any]
|
||||
'field-input': [field: CustomFieldInput, value: string]
|
||||
'field-blur': [field: CustomFieldInput]
|
||||
}>()
|
||||
|
||||
const layoutClass = computed(() =>
|
||||
@@ -170,16 +162,16 @@ const containerClass = computed(() =>
|
||||
const editable = computed(() => props.editable ?? true)
|
||||
const emitBlur = computed(() => props.emitBlur ?? true)
|
||||
|
||||
function isFieldEditable(field: any) {
|
||||
return props.isEditMode && editable.value && !resolveFieldReadOnly(field)
|
||||
function isFieldEditable(field: CustomFieldInput) {
|
||||
return props.isEditMode && editable.value && !field.readOnly
|
||||
}
|
||||
|
||||
function onInput(field: any, value: string) {
|
||||
function onInput(field: CustomFieldInput, value: string) {
|
||||
field.value = value
|
||||
emit('field-input', field, value)
|
||||
}
|
||||
|
||||
function onBooleanChange(field: any, checked: boolean) {
|
||||
function onBooleanChange(field: CustomFieldInput, checked: boolean) {
|
||||
const value = checked ? 'true' : 'false'
|
||||
field.value = value
|
||||
emit('field-input', field, value)
|
||||
@@ -188,7 +180,7 @@ function onBooleanChange(field: any, checked: boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
function onBlur(field: any) {
|
||||
function onBlur(field: CustomFieldInput) {
|
||||
if (emitBlur.value) {
|
||||
emit('field-blur', field)
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { fieldKey, type CustomFieldInput } from '~/shared/utils/customFieldFormUtils'
|
||||
import { fieldKey, type CustomFieldInput } from '~/shared/utils/customFields'
|
||||
|
||||
defineProps<{
|
||||
fields: CustomFieldInput[]
|
||||
|
||||
Reference in New Issue
Block a user