feat: dashboard Excel export button for full-access admins
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+59
-5
@@ -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="login-kicker">داشبورد کنترل</div>
|
||||
<h1 class="page-title">سلام، خوش آمدید</h1>
|
||||
<p class="page-sub">
|
||||
از اینجا به پنل پیامکی، سرور، افزونه، پشتیبانی، مدیران، نسخههای همکار / خانگی و سایتهای دیگر دسترسی دارید.
|
||||
</p>
|
||||
<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">
|
||||
|
||||
Reference in New Issue
Block a user