feat: dashboard Excel export button for full-access admins

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-27 20:44:34 +03:30
co-authored by Cursor
parent 47f5cf818a
commit f70b0f6c91
+54
View File
@@ -11,6 +11,7 @@ import {
GlobalOutlined,
LoginOutlined,
UserOutlined,
FileExcelOutlined,
} from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
import api from '@/api/http'
@@ -82,6 +83,50 @@ const canAdmins = computed(() => auth.can('admins:read'))
const canHamkar = computed(() => auth.canAny(productAnyReadPermissions('hamkar')))
const canKhanegi = computed(() => auth.canAny(productAnyReadPermissions('khanegi')))
const canOthers = computed(() => auth.can('others:read'))
const canExport = computed(() => auth.isFullAccess)
const exporting = ref(false)
async function downloadProjectsExcel() {
if (!canExport.value || exporting.value) return
exporting.value = true
try {
const { data, headers } = await api.get('/export/projects.xlsx', {
responseType: 'blob',
})
const disposition = String(headers?.['content-disposition'] || '')
const utfMatch = /filename\*=UTF-8''([^;]+)/i.exec(disposition)
const plainMatch = /filename="?([^";]+)"?/i.exec(disposition)
const filename = utfMatch
? decodeURIComponent(utfMatch[1])
: plainMatch?.[1] || 'superadmin-export.xlsx'
const url = URL.createObjectURL(new Blob([data]))
const a = document.createElement('a')
a.href = url
a.download = filename
document.body.appendChild(a)
a.click()
a.remove()
URL.revokeObjectURL(url)
message.success('خروجی اکسل آماده شد')
} catch (e: any) {
let msg = e?.response?.data?.message
const raw = e?.response?.data
if (raw instanceof Blob) {
try {
const text = await raw.text()
const parsed = JSON.parse(text)
msg = parsed?.message
} catch {
/* ignore */
}
}
message.error(
Array.isArray(msg) ? msg.join('، ') : msg || 'دانلود خروجی ناموفق بود',
)
} finally {
exporting.value = false
}
}
const modules = computed(() =>
[
@@ -246,11 +291,20 @@ onMounted(load)
<template>
<div class="page-shell">
<div class="page-head home-head">
<div class="page-head-text">
<div class="login-kicker">داشبورد کنترل</div>
<h1 class="page-title">سلام، خوش آمدید</h1>
<p class="page-sub">
از اینجا به پنل پیامکی، سرور، افزونه، پشتیبانی، مدیران، نسخه‌های همکار / خانگی و سایت‌های دیگر دسترسی دارید.
</p>
</div>
<div v-if="canExport" class="page-head-actions">
<a-button type="primary" :loading="exporting" @click="downloadProjectsExcel">
<FileExcelOutlined /> خروجی اکسل پروژه‌ها
</a-button>
</div>
</div>
<a-spin :spinning="loading">
<div class="dash-modules">