76 lines
2.9 KiB
Vue
76 lines
2.9 KiB
Vue
<script setup lang="ts">
|
||||
|
|
import { onMounted, ref } from 'vue';
|
|||
|
|
import { RouterLink } from 'vue-router';
|
|||
|
|
import type { DiscDistributionRow } from '@mento/shared';
|
|||
|
|
import { api } from '@/lib/api';
|
|||
|
|
import { toFaDigits } from '@/lib/jalali';
|
|||
|
|
import { UiButton, UiPageHeader } from '@/components/ui';
|
|||
|
|
|
|||
|
|
const rows = ref<DiscDistributionRow[]>([]);
|
|||
|
|
const error = ref('');
|
|||
|
|
const loading = ref(true);
|
|||
|
|
const exporting = ref(false);
|
|||
|
|
|
|||
|
|
onMounted(async () => {
|
|||
|
|
try {
|
|||
|
|
const { data } = await api.get<DiscDistributionRow[]>('/behavior/disc/distribution');
|
|||
|
|
rows.value = data;
|
|||
|
|
} catch {
|
|||
|
|
error.value = 'گزارش توزیع تیپها بارگذاری نشد.';
|
|||
|
|
} finally {
|
|||
|
|
loading.value = false;
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
async function exportExcel() {
|
|||
|
|
exporting.value = true;
|
|||
|
|
error.value = '';
|
|||
|
|
try {
|
|||
|
|
const { data } = await api.get<Blob>('/behavior/disc/export', { responseType: 'blob' });
|
|||
|
|
const url = URL.createObjectURL(data);
|
|||
|
|
const link = document.createElement('a');
|
|||
|
|
link.href = url;
|
|||
|
|
link.download = 'disc.xlsx';
|
|||
|
|
link.click();
|
|||
|
|
URL.revokeObjectURL(url);
|
|||
|
|
} catch {
|
|||
|
|
error.value = 'خروجی اکسل ناموفق بود.';
|
|||
|
|
} finally {
|
|||
|
|
exporting.value = false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const total = () => rows.value.reduce((sum, row) => sum + row.count, 0);
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<template>
|
|||
|
|
<section class="page">
|
|||
|
|
<UiPageHeader title="توزیع تیپهای DISC" lead="فقط ارزیابیهای تأییدشده و قابل اتکا، در محدودهٔ دسترسی شما" :back-to="{ name: 'contacts' }">
|
|||
|
|
<template #actions>
|
|||
|
|
<UiButton variant="outline" :disabled="exporting" @click="exportExcel">خروجی اکسل</UiButton>
|
|||
|
|
</template>
|
|||
|
|
</UiPageHeader>
|
|||
|
|
<p v-if="loading" class="muted">در حال بارگذاری…</p>
|
|||
|
|
<p v-else-if="error" class="error">{{ error }}</p>
|
|||
|
|
<p v-else-if="!rows.length" class="muted">هنوز تیپ قابل اتکایی ثبت نشده است.</p>
|
|||
|
|
<ul v-else class="list">
|
|||
|
|
<li v-for="row in rows" :key="row.label">
|
|||
|
|
<RouterLink :to="{ name: 'contacts', query: { disc: row.label } }">{{ row.label }}</RouterLink>
|
|||
|
|
<span>{{ toFaDigits(row.count) }}</span>
|
|||
|
|
<i><b :style="{ width: `${total() ? Math.round((row.count / total()) * 100) : 0}%` }" /></i>
|
|||
|
|
</li>
|
|||
|
|
</ul>
|
|||
|
|
<p class="muted">درصدها سهم مشتریان دارای ارزیابی معتبر هستند، نه دقت یک آزمون روانشناسی.</p>
|
|||
|
|
</section>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
.page { display: flex; flex-direction: column; gap: 0.8rem; }
|
|||
|
|
.list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.55rem; }
|
|||
|
|
.list li { display: grid; grid-template-columns: 6rem auto 1fr; gap: 0.6rem; align-items: center; }
|
|||
|
|
.list i { height: 8px; background: #e2e8f0; border-radius: 99px; overflow: hidden; }
|
|||
|
|
.list b { display: block; height: 100%; background: #0f766e; }
|
|||
|
|
.muted { color: #64748b; }
|
|||
|
|
.error { color: #b91c1c; }
|
|||
|
|
</style>
|