Files
CRM_Montzar/apps/web/src/views/LeadFormsSettingsView.vue
T
s.esmaeili 1ae87c97b7 feat(ui): standardize design system, modals, sidebar, and form inputs
- Implement unified design system tokens, 10px radius, and IRANSans typography
- Modernize sidebar with Gemini-style collapsed expander, square 1:1 items, and elevated profile flyout
- Standardize all modal dialogs with 16px padding, fixed header/footer, 16px medium title, and sticky bottom actions
- Refactor DealFormView and CustomFieldsSection with standard UiField, UiInput, and UiSelect components
- Add draggable bottom-left QuickCreate floating action button
2026-09-12 01:33:07 +03:30

252 lines
6.5 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import { RouterLink, useRouter } from 'vue-router';
import axios from 'axios';
import { api } from '@/lib/api';
import {
UiBadge,
UiButton,
UiCard,
UiEmptyState,
UiPageHeader,
} from '@/components/ui';
import UiIcon from '@/components/UiIcon.vue';
import type { LeadFormDto } from '@mento/shared';
import { toFaDigits } from '@/lib/jalali';
const router = useRouter();
const loading = ref(false);
const saving = ref(false);
const error = ref('');
const forms = ref<LeadFormDto[]>([]);
async function load() {
loading.value = true;
error.value = '';
try {
const { data } = await api.get<LeadFormDto[]>('/lead-forms');
forms.value = data;
} catch (e) {
error.value = axios.isAxiosError(e) && !e.response
? 'اتصال به API برقرار نشد.'
: 'بارگذاری فرم‌ها ناموفق بود.';
} finally {
loading.value = false;
}
}
async function createForm() {
saving.value = true;
error.value = '';
try {
const { data } = await api.post<LeadFormDto>('/lead-forms', {
name: 'درخواست مشاوره',
description: 'فرم دریافت درخواست مشاوره مشتریان',
source: 'وب‌سایت',
createPerson: true,
createDeal: true,
});
await router.push({ name: 'lead-form-builder', params: { id: data.id } });
} catch {
error.value = 'ساخت فرم ناموفق بود.';
} finally {
saving.value = false;
}
}
async function removeForm(form: LeadFormDto) {
if (!confirm(`فرم «${form.name}» حذف شود؟`)) return;
await api.delete(`/lead-forms/${form.id}`);
await load();
}
const countLabel = computed(() => toFaDigits(forms.value.length));
onMounted(load);
</script>
<template>
<section class="crm-page lead-forms-page" dir="rtl">
<UiPageHeader
title="فرم‌ساز وب"
description="فرم‌های آنلاین بسازید، فیلدها را بچینید و لیدها را به صورت خودکار در کاریز و باشگاه مشتریان دریافت کنید."
>
<template #actions>
<UiButton :loading="saving" @click="createForm">
<template #icon>
<UiIcon name="plus" />
</template>
فرم جدید
</UiButton>
</template>
</UiPageHeader>
<div v-if="error" class="crm-alert crm-alert-danger">{{ error }}</div>
<div v-else-if="!loading && forms.length" class="forms-summary">
<span class="forms-count-badge">{{ countLabel }} فرم ساخته شده</span>
</div>
<UiEmptyState
v-if="!loading && !forms.length"
title="هنوز فرمی نساخته‌اید"
description="با ساخت اولین فرم، می‌توانید در وب‌سایت یا شبکه‌های اجتماعی سرنخ و مشتری جذب کنید."
icon="document"
>
<template #action>
<UiButton :loading="saving" @click="createForm">
<template #icon>
<UiIcon name="plus" />
</template>
ساخت اولین فرم
</UiButton>
</template>
</UiEmptyState>
<div v-else class="forms-list">
<UiCard v-for="form in forms" :key="form.id" class="form-card">
<div class="form-info">
<div class="form-title-row">
<strong class="form-name">{{ form.name }}</strong>
<UiBadge :variant="form.isActive ? 'success' : 'neutral'">
{{ form.isActive ? 'فعال' : 'غیرفعال' }}
</UiBadge>
</div>
<p class="form-meta">
<span>{{ toFaDigits(form.fields.length) }} فیلد سفارشی</span>
<span class="meta-dot">·</span>
<span>{{ toFaDigits(form.submissionCount ?? 0) }} ارسال شده</span>
<span v-if="form.source" class="meta-dot">·</span>
<span v-if="form.source">منبع: {{ form.source }}</span>
</p>
</div>
<div class="form-actions">
<RouterLink :to="{ name: 'lead-form-builder', params: { id: form.id } }">
<UiButton variant="secondary" size="sm">
<template #icon>
<UiIcon name="pencil" />
</template>
ویرایش فیلدها
</UiButton>
</RouterLink>
<a :href="form.publicPath" target="_blank" rel="noopener" class="preview-link">
<UiButton variant="ghost" size="sm">
<template #icon>
<UiIcon name="eye" />
</template>
پیش‌نمایش
</UiButton>
</a>
<UiButton variant="danger" size="sm" @click="removeForm(form)">
<template #icon>
<UiIcon name="trash" />
</template>
حذف
</UiButton>
</div>
</UiCard>
</div>
</section>
</template>
<style scoped>
.lead-forms-page {
display: flex;
flex-direction: column;
gap: var(--sp-6);
width: 100%;
max-width: 100%;
}
.forms-summary {
display: flex;
align-items: center;
}
.forms-count-badge {
font-size: var(--fs-sm);
color: var(--color-text-secondary);
background: var(--color-surface-soft);
padding: var(--sp-1) var(--sp-3);
border-radius: var(--radius-full);
border: 1px solid var(--color-border);
}
.forms-list {
display: flex;
flex-direction: column;
gap: var(--sp-4);
}
.form-card {
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--sp-4);
padding: var(--sp-4) var(--sp-5);
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.form-card:hover {
border-color: var(--color-brand-300, #5eead4);
box-shadow: var(--shadow-sm);
}
.form-info {
display: flex;
flex-direction: column;
gap: var(--sp-1);
}
.form-title-row {
display: flex;
align-items: center;
gap: var(--sp-3);
}
.form-name {
font-size: var(--fs-md);
font-weight: 700;
color: var(--color-text-primary);
}
.form-meta {
margin: 0;
font-size: var(--fs-xs);
color: var(--color-text-secondary);
display: flex;
align-items: center;
gap: var(--sp-2);
}
.meta-dot {
color: var(--color-text-muted);
}
.form-actions {
display: flex;
align-items: center;
gap: var(--sp-2);
flex-wrap: wrap;
}
.preview-link {
text-decoration: none;
}
@media (max-width: 640px) {
.form-card {
flex-direction: column;
align-items: flex-start;
}
.form-actions {
width: 100%;
justify-content: flex-end;
}
}
</style>