Unify the web UI on shared controls and let pipeline columns be managed on the board.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-10 01:22:24 +03:30
co-authored by Cursor
parent f1aba1b386
commit b8ad4037b6
40 changed files with 2334 additions and 788 deletions
+38 -15
View File
@@ -9,7 +9,10 @@ import {
toFaDigits,
} from '@/lib/jalali';
import JalaliDateInput from '@/components/JalaliDateInput.vue';
import UiButton from '@/components/ui/UiButton.vue';
import UiModal from '@/components/ui/UiModal.vue';
import UiIcon from '@/components/UiIcon.vue';
import InvoiceFormView from '@/views/InvoiceFormView.vue';
import type {
InvoiceDto,
PaginatedResponse,
@@ -71,6 +74,7 @@ const selected = ref<Set<string>>(new Set());
const menuId = ref<string | null>(null);
const filterSheet = ref(false);
const addOpen = ref(false);
const invoiceModal = ref<{ kind: 'invoice' | 'credit' | 'quote' } | null>(null);
function mapInvoiceStatus(inv: InvoiceDto): { key: PayFilter; label: string } {
if (inv.status === 'paid') return { key: 'paid', label: 'پرداخت شده' };
@@ -349,25 +353,23 @@ onMounted(load);
</div>
<div class="head-actions" @click.stop>
<div class="add-split desk-only">
<RouterLink class="btn primary" :to="{ name: 'invoice-new' }">
<UiIcon name="plus" :size="18" />
<UiButton type="button" @click="invoiceModal = { kind: 'invoice' }; addOpen = false">
<UiIcon name="plus" :size="16" />
افزودن فاکتور
</RouterLink>
</UiButton>
<button type="button" class="btn primary split" aria-label="گزینه‌های افزودن" @click="addOpen = !addOpen">
<UiIcon name="chevron" :size="14" />
</button>
<div v-if="addOpen" class="menu">
<RouterLink :to="{ name: 'invoice-new' }">فاکتور جدید</RouterLink>
<RouterLink :to="{ name: 'quote-new' }">پیش فاکتور جدید</RouterLink>
<RouterLink :to="{ name: 'invoice-new', query: { kind: 'credit' } }">
فاکتور برگشتی
</RouterLink>
<button type="button" @click="invoiceModal = { kind: 'invoice' }; addOpen = false">فاکتور جدید</button>
<button type="button" @click="invoiceModal = { kind: 'quote' }; addOpen = false">پیش فاکتور جدید</button>
<button type="button" @click="invoiceModal = { kind: 'credit' }; addOpen = false">فاکتور برگشتی</button>
</div>
</div>
<RouterLink class="icon-btn add-doc mob-only" :to="{ name: 'invoice-new' }" aria-label="افزودن">
<UiIcon name="document" :size="18" />
<UiIcon name="plus" :size="12" class="plus-badge" />
</RouterLink>
<UiButton class="mob-only" type="button" @click="invoiceModal = { kind: 'invoice' }">
<UiIcon name="plus" :size="16" />
افزودن
</UiButton>
</div>
</header>
@@ -596,7 +598,25 @@ onMounted(load);
</footer>
</template>
<RouterLink class="fab" :to="{ name: 'invoice-new' }">افزودن فاکتور +</RouterLink>
<UiModal
:open="Boolean(invoiceModal)"
:title="
invoiceModal?.kind === 'quote'
? 'پیش فاکتور جدید'
: invoiceModal?.kind === 'credit'
? 'فاکتور برگشتی'
: 'فاکتور جدید'
"
@close="invoiceModal = null"
>
<InvoiceFormView
v-if="invoiceModal"
embedded
:initial-kind="invoiceModal.kind"
@saved="invoiceModal = null; void load()"
@cancel="invoiceModal = null"
/>
</UiModal>
<div v-if="filterSheet" class="sheet-backdrop" @click="filterSheet = false">
<div class="sheet" @click.stop>
@@ -708,11 +728,14 @@ h1 { margin: 0; font-size: 1.5rem; font-weight: 800; }
box-shadow: 0 12px 28px rgba(15,23,42,.12); padding: 0.35rem; display: grid;
}
.menu.left { left: auto; right: 0; }
.menu a {
.menu a,
.menu button {
display: block; width: 100%;
border: 0; background: transparent; text-align: right; padding: 0.55rem 0.7rem;
border-radius: 8px; color: var(--text); text-decoration: none; cursor: pointer;
}
.menu a:hover { background: var(--teal-soft); color: var(--teal); }
.menu a:hover,
.menu button:hover { background: var(--teal-soft); color: var(--teal); }
.tabs {
display: flex; gap: 0.35rem; overflow-x: auto; border-bottom: 1px solid var(--line);