mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-27 05:36:43 +08:00
feat(projects): add plugin excel export
This commit is contained in:
parent
447bda2b48
commit
06b0dc6aef
@ -75,7 +75,8 @@
|
||||
"vue-i18n": "9.13.1",
|
||||
"vue-router": "4.4.0",
|
||||
"wangeditor": "4.7.15",
|
||||
"xgplayer": "3.0.17"
|
||||
"xgplayer": "3.0.17",
|
||||
"xlsx": "0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@amap/amap-jsapi-types": "0.0.8",
|
||||
|
@ -196,7 +196,8 @@ const local: App.I18n.Schema = {
|
||||
plugin_swiper: 'Swiper',
|
||||
plugin_video: 'Video',
|
||||
plugin_barcode: 'Barcode',
|
||||
plugin_pinyin: 'pinyin'
|
||||
plugin_pinyin: 'pinyin',
|
||||
plugin_excel: 'Excel'
|
||||
},
|
||||
page: {
|
||||
login: {
|
||||
|
@ -196,7 +196,8 @@ const local: App.I18n.Schema = {
|
||||
plugin_swiper: 'Swiper',
|
||||
plugin_video: '视频',
|
||||
plugin_barcode: '条形码',
|
||||
plugin_pinyin: '拼音'
|
||||
plugin_pinyin: '拼音',
|
||||
plugin_excel: 'Excel'
|
||||
},
|
||||
page: {
|
||||
login: {
|
||||
|
@ -41,6 +41,7 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
|
||||
plugin_copy: () => import("@/views/plugin/copy/index.vue"),
|
||||
plugin_editor_markdown: () => import("@/views/plugin/editor/markdown/index.vue"),
|
||||
plugin_editor_quill: () => import("@/views/plugin/editor/quill/index.vue"),
|
||||
plugin_excel: () => import("@/views/plugin/excel/index.vue"),
|
||||
plugin_icon: () => import("@/views/plugin/icon/index.vue"),
|
||||
plugin_map: () => import("@/views/plugin/map/index.vue"),
|
||||
plugin_pinyin: () => import("@/views/plugin/pinyin/index.vue"),
|
||||
|
@ -413,6 +413,17 @@ export const generatedRoutes: GeneratedRoute[] = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'plugin_excel',
|
||||
path: '/plugin/excel',
|
||||
component: 'view.plugin_excel',
|
||||
meta: {
|
||||
title: 'plugin_excel',
|
||||
i18nKey: 'route.plugin_excel',
|
||||
icon: 'ri:file-excel-2-line',
|
||||
keepAlive: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'plugin_icon',
|
||||
path: '/plugin/icon',
|
||||
|
@ -209,6 +209,7 @@ const routeMap: RouteMap = {
|
||||
"plugin_editor": "/plugin/editor",
|
||||
"plugin_editor_markdown": "/plugin/editor/markdown",
|
||||
"plugin_editor_quill": "/plugin/editor/quill",
|
||||
"plugin_excel": "/plugin/excel",
|
||||
"plugin_icon": "/plugin/icon",
|
||||
"plugin_map": "/plugin/map",
|
||||
"plugin_pinyin": "/plugin/pinyin",
|
||||
|
1
src/typings/components.d.ts
vendored
1
src/typings/components.d.ts
vendored
@ -18,6 +18,7 @@ declare module 'vue' {
|
||||
IconAntDesignEnterOutlined: typeof import('~icons/ant-design/enter-outlined')['default']
|
||||
IconAntDesignReloadOutlined: typeof import('~icons/ant-design/reload-outlined')['default']
|
||||
IconAntDesignSettingOutlined: typeof import('~icons/ant-design/setting-outlined')['default']
|
||||
'IconFileIcons:microsoftExcel': typeof import('~icons/file-icons/microsoft-excel')['default']
|
||||
IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
|
||||
IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
|
||||
'IconIc:roundPlus': typeof import('~icons/ic/round-plus')['default']
|
||||
|
2
src/typings/elegant-router.d.ts
vendored
2
src/typings/elegant-router.d.ts
vendored
@ -65,6 +65,7 @@ declare module "@elegant-router/types" {
|
||||
"plugin_editor": "/plugin/editor";
|
||||
"plugin_editor_markdown": "/plugin/editor/markdown";
|
||||
"plugin_editor_quill": "/plugin/editor/quill";
|
||||
"plugin_excel": "/plugin/excel";
|
||||
"plugin_icon": "/plugin/icon";
|
||||
"plugin_map": "/plugin/map";
|
||||
"plugin_pinyin": "/plugin/pinyin";
|
||||
@ -171,6 +172,7 @@ declare module "@elegant-router/types" {
|
||||
| "plugin_copy"
|
||||
| "plugin_editor_markdown"
|
||||
| "plugin_editor_quill"
|
||||
| "plugin_excel"
|
||||
| "plugin_icon"
|
||||
| "plugin_map"
|
||||
| "plugin_pinyin"
|
||||
|
171
src/views/plugin/excel/index.vue
Normal file
171
src/views/plugin/excel/index.vue
Normal file
@ -0,0 +1,171 @@
|
||||
<script setup lang="tsx">
|
||||
import { NButton, NTag } from 'naive-ui';
|
||||
import { utils, writeFile } from 'xlsx';
|
||||
import type { DataTableBaseColumn } from 'naive-ui';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useTable } from '@/hooks/common/table';
|
||||
import { fetchGetUserList } from '@/service/api';
|
||||
import { enableStatusRecord, userGenderRecord } from '@/constants/business';
|
||||
import { $t } from '@/locales';
|
||||
const appStore = useAppStore();
|
||||
|
||||
const { columns, data, loading } = useTable({
|
||||
apiFn: fetchGetUserList,
|
||||
showTotal: true,
|
||||
apiParams: {
|
||||
current: 1,
|
||||
size: 999,
|
||||
// if you want to use the searchParams in Form, you need to define the following properties, and the value is null
|
||||
// the value can not be undefined, otherwise the property in Form will not be reactive
|
||||
status: null,
|
||||
userName: null,
|
||||
userGender: null,
|
||||
nickName: null,
|
||||
userPhone: null,
|
||||
userEmail: null
|
||||
},
|
||||
columns: () => [
|
||||
{
|
||||
type: 'selection',
|
||||
align: 'center',
|
||||
width: 48
|
||||
},
|
||||
{
|
||||
key: 'index',
|
||||
title: $t('common.index'),
|
||||
align: 'center',
|
||||
width: 64
|
||||
},
|
||||
{
|
||||
key: 'userName',
|
||||
title: $t('page.manage.user.userName'),
|
||||
align: 'center',
|
||||
minWidth: 100
|
||||
},
|
||||
{
|
||||
key: 'userGender',
|
||||
title: $t('page.manage.user.userGender'),
|
||||
align: 'center',
|
||||
width: 100,
|
||||
render: row => {
|
||||
if (row.userGender === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tagMap: Record<Api.SystemManage.UserGender, NaiveUI.ThemeColor> = {
|
||||
1: 'primary',
|
||||
2: 'error'
|
||||
};
|
||||
|
||||
const label = $t(userGenderRecord[row.userGender]);
|
||||
|
||||
return <NTag type={tagMap[row.userGender]}>{label}</NTag>;
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'nickName',
|
||||
title: $t('page.manage.user.nickName'),
|
||||
align: 'center',
|
||||
minWidth: 100
|
||||
},
|
||||
{
|
||||
key: 'userPhone',
|
||||
title: $t('page.manage.user.userPhone'),
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
key: 'userEmail',
|
||||
title: $t('page.manage.user.userEmail'),
|
||||
align: 'center',
|
||||
minWidth: 200
|
||||
},
|
||||
{
|
||||
key: 'status',
|
||||
title: $t('page.manage.user.userStatus'),
|
||||
align: 'center',
|
||||
width: 100,
|
||||
render: row => {
|
||||
if (row.status === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tagMap: Record<Api.Common.EnableStatus, NaiveUI.ThemeColor> = {
|
||||
1: 'success',
|
||||
2: 'warning'
|
||||
};
|
||||
|
||||
const label = $t(enableStatusRecord[row.status]);
|
||||
|
||||
return <NTag type={tagMap[row.status]}>{label}</NTag>;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
const customRenderText = {
|
||||
status(row: Api.SystemManage.User) {
|
||||
return $t(enableStatusRecord[row.status as Api.Common.EnableStatus]);
|
||||
},
|
||||
userGender(row: Api.SystemManage.User) {
|
||||
return $t(userGenderRecord[row.userGender as Api.SystemManage.UserGender]);
|
||||
}
|
||||
};
|
||||
const tableTitleList = columns.value.slice(2) as DataTableBaseColumn[];
|
||||
function exportExcel() {
|
||||
const excelList = data.value.map(item =>
|
||||
tableTitleList.map(col => {
|
||||
if (col.render) {
|
||||
const title = col.key as keyof typeof customRenderText;
|
||||
|
||||
return customRenderText[title](item);
|
||||
}
|
||||
return item[col.key as keyof typeof item];
|
||||
})
|
||||
);
|
||||
const titleList = tableTitleList.map(item => item.title) as string[];
|
||||
|
||||
excelList.unshift(titleList);
|
||||
const workBook = utils.book_new();
|
||||
const workSheet = utils.aoa_to_sheet(excelList);
|
||||
workSheet['!cols'] = tableTitleList.map(item => ({
|
||||
width: Math.round(Number(item.width) / 10 || 20)
|
||||
}));
|
||||
|
||||
utils.book_append_sheet(workBook, workSheet, '用户列表');
|
||||
|
||||
writeFile(workBook, '用户数据.xlsx');
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
||||
<NCard title="Excel导出" :bordered="false" size="small" class="sm:flex-1-hidden card-wrapper">
|
||||
<template #header-extra>
|
||||
<NSpace align="end" wrap justify="end" class="lt-sm:w-200px">
|
||||
<NButton size="small" ghost type="primary" @click="exportExcel">
|
||||
<template #icon>
|
||||
<icon-file-icons:microsoft-excel class="text-icon" />
|
||||
</template>
|
||||
导出excel
|
||||
</NButton>
|
||||
</NSpace>
|
||||
</template>
|
||||
|
||||
<NDataTable
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
size="small"
|
||||
:flex-height="!appStore.isMobile"
|
||||
:scroll-x="962"
|
||||
:loading="loading"
|
||||
remote
|
||||
:row-key="row => row.id"
|
||||
:pagination="false"
|
||||
:virtual-scroll="true"
|
||||
class="sm:h-full"
|
||||
/>
|
||||
</NCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
Loading…
Reference in New Issue
Block a user