2026-08-29 21:06:30 +03:30
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { onMounted, ref, watch } from 'vue';
|
|
|
|
|
import { api } from '@/lib/api';
|
2026-09-02 21:29:00 +03:30
|
|
|
import JalaliDateInput from '@/components/JalaliDateInput.vue';
|
2026-09-12 01:33:07 +03:30
|
|
|
import { UiField, UiInput, UiSelect } from '@/components/ui';
|
2026-08-29 21:06:30 +03:30
|
|
|
import type {
|
|
|
|
|
CustomFieldDefinitionDto,
|
|
|
|
|
CustomFieldEntity,
|
|
|
|
|
} from '@mento/shared';
|
|
|
|
|
|
|
|
|
|
const props = defineProps<{
|
|
|
|
|
entityType: CustomFieldEntity;
|
|
|
|
|
modelValue: Record<string, unknown>;
|
|
|
|
|
}>();
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits<{
|
|
|
|
|
'update:modelValue': [value: Record<string, unknown>];
|
|
|
|
|
}>();
|
|
|
|
|
|
|
|
|
|
const fields = ref<CustomFieldDefinitionDto[]>([]);
|
|
|
|
|
const loading = ref(false);
|
|
|
|
|
|
|
|
|
|
async function load() {
|
|
|
|
|
loading.value = true;
|
|
|
|
|
try {
|
|
|
|
|
fields.value = (
|
|
|
|
|
await api.get<CustomFieldDefinitionDto[]>('/custom-fields', {
|
|
|
|
|
params: { entityType: props.entityType, activeOnly: true },
|
|
|
|
|
})
|
|
|
|
|
).data;
|
|
|
|
|
} catch {
|
|
|
|
|
fields.value = [];
|
|
|
|
|
} finally {
|
|
|
|
|
loading.value = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setValue(key: string, value: unknown) {
|
|
|
|
|
emit('update:modelValue', { ...props.modelValue, [key]: value });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function displayValue(key: string) {
|
|
|
|
|
const v = props.modelValue[key];
|
|
|
|
|
if (v == null) return '';
|
|
|
|
|
if (typeof v === 'boolean') return v;
|
|
|
|
|
return String(v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
() => props.entityType,
|
|
|
|
|
() => {
|
|
|
|
|
void load();
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
onMounted(load);
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<div v-if="loading" class="muted">بارگذاری فیلدهای سفارشی…</div>
|
|
|
|
|
<div v-else-if="fields.length" class="custom-block">
|
2026-09-12 01:33:07 +03:30
|
|
|
<h3 class="custom-title">فیلدهای سفارشی</h3>
|
|
|
|
|
<div class="crm-form-grid-2">
|
|
|
|
|
<UiField
|
|
|
|
|
v-for="field in fields"
|
|
|
|
|
:key="field.id"
|
|
|
|
|
:label="field.label"
|
|
|
|
|
:required="field.required"
|
|
|
|
|
:for-id="`cf-${field.key}`"
|
|
|
|
|
>
|
|
|
|
|
<UiSelect
|
2026-08-29 21:06:30 +03:30
|
|
|
v-if="field.fieldType === 'select'"
|
|
|
|
|
:id="`cf-${field.key}`"
|
2026-09-12 01:33:07 +03:30
|
|
|
:model-value="String(displayValue(field.key))"
|
|
|
|
|
@update:model-value="setValue(field.key, $event)"
|
2026-08-29 21:06:30 +03:30
|
|
|
>
|
|
|
|
|
<option value="">انتخاب کنید</option>
|
|
|
|
|
<option v-for="opt in field.options" :key="opt" :value="opt">
|
|
|
|
|
{{ opt }}
|
|
|
|
|
</option>
|
2026-09-12 01:33:07 +03:30
|
|
|
</UiSelect>
|
2026-08-29 21:06:30 +03:30
|
|
|
|
2026-09-12 01:33:07 +03:30
|
|
|
<label v-else-if="field.fieldType === 'boolean'" class="cf-check">
|
2026-08-29 21:06:30 +03:30
|
|
|
<input
|
|
|
|
|
:id="`cf-${field.key}`"
|
|
|
|
|
type="checkbox"
|
|
|
|
|
:checked="Boolean(props.modelValue[field.key])"
|
|
|
|
|
@change="
|
|
|
|
|
setValue(field.key, ($event.target as HTMLInputElement).checked)
|
|
|
|
|
"
|
|
|
|
|
/>
|
2026-09-12 01:33:07 +03:30
|
|
|
<span>فعال</span>
|
2026-08-29 21:06:30 +03:30
|
|
|
</label>
|
|
|
|
|
|
2026-09-12 01:33:07 +03:30
|
|
|
<UiInput
|
2026-08-29 21:06:30 +03:30
|
|
|
v-else-if="field.fieldType === 'number'"
|
|
|
|
|
:id="`cf-${field.key}`"
|
|
|
|
|
type="number"
|
2026-09-12 01:33:07 +03:30
|
|
|
:model-value="props.modelValue[field.key] != null ? Number(props.modelValue[field.key]) : ''"
|
|
|
|
|
@update:model-value="
|
2026-08-29 21:06:30 +03:30
|
|
|
setValue(
|
|
|
|
|
field.key,
|
2026-09-12 01:33:07 +03:30
|
|
|
$event === '' || $event == null ? null : Number($event),
|
2026-08-29 21:06:30 +03:30
|
|
|
)
|
|
|
|
|
"
|
|
|
|
|
/>
|
|
|
|
|
|
2026-09-02 21:29:00 +03:30
|
|
|
<JalaliDateInput
|
2026-08-29 21:06:30 +03:30
|
|
|
v-else-if="field.fieldType === 'date'"
|
|
|
|
|
:id="`cf-${field.key}`"
|
2026-09-02 21:29:00 +03:30
|
|
|
:model-value="String(displayValue(field.key))"
|
|
|
|
|
@update:model-value="setValue(field.key, $event || null)"
|
2026-08-29 21:06:30 +03:30
|
|
|
/>
|
|
|
|
|
|
2026-09-12 01:33:07 +03:30
|
|
|
<UiInput
|
2026-08-29 21:06:30 +03:30
|
|
|
v-else
|
|
|
|
|
:id="`cf-${field.key}`"
|
|
|
|
|
type="text"
|
2026-09-12 01:33:07 +03:30
|
|
|
:model-value="String(displayValue(field.key))"
|
|
|
|
|
@update:model-value="setValue(field.key, $event)"
|
2026-08-29 21:06:30 +03:30
|
|
|
/>
|
2026-09-12 01:33:07 +03:30
|
|
|
</UiField>
|
2026-08-29 21:06:30 +03:30
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.custom-block {
|
2026-09-12 01:33:07 +03:30
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
gap: var(--sp-3);
|
|
|
|
|
padding-top: var(--sp-4);
|
2026-08-29 21:06:30 +03:30
|
|
|
border-top: 1px dashed var(--line);
|
2026-09-12 01:33:07 +03:30
|
|
|
width: 100%;
|
2026-08-29 21:06:30 +03:30
|
|
|
}
|
|
|
|
|
|
2026-09-12 01:33:07 +03:30
|
|
|
.custom-title {
|
2026-08-29 21:06:30 +03:30
|
|
|
margin: 0;
|
2026-09-12 01:33:07 +03:30
|
|
|
font-size: var(--fs-sm);
|
|
|
|
|
font-weight: var(--fw-semibold);
|
|
|
|
|
color: var(--ink-secondary);
|
2026-08-29 21:06:30 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.muted {
|
|
|
|
|
color: var(--muted);
|
2026-09-12 01:33:07 +03:30
|
|
|
font-size: var(--fs-xs);
|
2026-08-29 21:06:30 +03:30
|
|
|
}
|
|
|
|
|
|
2026-09-12 01:33:07 +03:30
|
|
|
.cf-check {
|
|
|
|
|
display: inline-flex;
|
2026-08-29 21:06:30 +03:30
|
|
|
align-items: center;
|
2026-09-12 01:33:07 +03:30
|
|
|
gap: var(--sp-2);
|
|
|
|
|
min-height: var(--control-h-md);
|
|
|
|
|
font-size: var(--fs-base);
|
|
|
|
|
font-weight: var(--fw-medium);
|
|
|
|
|
color: var(--ink);
|
|
|
|
|
cursor: pointer;
|
2026-08-29 21:06:30 +03:30
|
|
|
}
|
|
|
|
|
|
2026-09-12 01:33:07 +03:30
|
|
|
.cf-check input[type='checkbox'] {
|
|
|
|
|
width: 18px;
|
|
|
|
|
height: 18px;
|
|
|
|
|
accent-color: var(--accent);
|
|
|
|
|
cursor: pointer;
|
2026-08-29 21:06:30 +03:30
|
|
|
}
|
|
|
|
|
</style>
|