mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-27 19:44:50 +08:00
perf: perf excel comp code
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
# Wip
|
# Wip
|
||||||
|
|
||||||
|
### 🎫 Chores
|
||||||
|
|
||||||
|
- 表格默认不显示边框
|
||||||
|
|
||||||
### ⚡ Performance Improvements
|
### ⚡ Performance Improvements
|
||||||
|
|
||||||
- 优化首屏体积大小
|
- 优化首屏体积大小
|
||||||
|
@@ -19,16 +19,17 @@ export default defineComponent({
|
|||||||
const getModeRef = computed(() => {
|
const getModeRef = computed(() => {
|
||||||
return appStore.getProjectConfig.permissionMode;
|
return appStore.getProjectConfig.permissionMode;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渲染角色按钮
|
* 渲染角色按钮
|
||||||
*/
|
*/
|
||||||
function renderRoleAuth() {
|
function renderRoleAuth() {
|
||||||
const { value } = props;
|
const { value } = props;
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return getSlot(slots, 'default');
|
return getSlot(slots);
|
||||||
}
|
}
|
||||||
const { hasPermission } = usePermission();
|
const { hasPermission } = usePermission();
|
||||||
return hasPermission(value) ? getSlot(slots, 'default') : null;
|
return hasPermission(value) ? getSlot(slots) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,11 +39,12 @@ export default defineComponent({
|
|||||||
function renderCodeAuth() {
|
function renderCodeAuth() {
|
||||||
const { value } = props;
|
const { value } = props;
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return getSlot(slots, 'default');
|
return getSlot(slots);
|
||||||
}
|
}
|
||||||
const { hasPermission } = usePermission();
|
const { hasPermission } = usePermission();
|
||||||
return hasPermission(value) ? getSlot(slots, 'default') : null;
|
return hasPermission(value) ? getSlot(slots) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
const mode = unref(getModeRef);
|
const mode = unref(getModeRef);
|
||||||
// 基于角色渲染
|
// 基于角色渲染
|
||||||
@@ -53,7 +55,7 @@ export default defineComponent({
|
|||||||
if (mode === PermissionModeEnum.BACK) {
|
if (mode === PermissionModeEnum.BACK) {
|
||||||
return renderCodeAuth();
|
return renderCodeAuth();
|
||||||
}
|
}
|
||||||
return getSlot(slots, 'default');
|
return getSlot(slots);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@@ -33,18 +33,7 @@ export default defineComponent({
|
|||||||
props: basicProps,
|
props: basicProps,
|
||||||
emits: ['visible-change', 'ok', 'close', 'register'],
|
emits: ['visible-change', 'ok', 'close', 'register'],
|
||||||
setup(props, { slots, emit, attrs }) {
|
setup(props, { slots, emit, attrs }) {
|
||||||
// const { currentRoute } = useRouter();
|
|
||||||
const scrollRef = ref<any>(null);
|
const scrollRef = ref<any>(null);
|
||||||
// /**
|
|
||||||
// * @description: 获取配置ScrollContainer
|
|
||||||
// */
|
|
||||||
// const getScrollOptions = computed(
|
|
||||||
// (): ScrollContainerOptions => {
|
|
||||||
// return {
|
|
||||||
// ...(props.scrollOptions as any),
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
|
|
||||||
const visibleRef = ref(false);
|
const visibleRef = ref(false);
|
||||||
const propsRef = ref<Partial<DrawerProps> | null>(null);
|
const propsRef = ref<Partial<DrawerProps> | null>(null);
|
||||||
@@ -85,7 +74,6 @@ export default defineComponent({
|
|||||||
watch(
|
watch(
|
||||||
() => visibleRef.value,
|
() => visibleRef.value,
|
||||||
(visible) => {
|
(visible) => {
|
||||||
// appStore.commitLockMainScrollState(visible);
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
emit('visible-change', visible);
|
emit('visible-change', visible);
|
||||||
});
|
});
|
||||||
@@ -95,27 +83,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// function scrollBottom() {
|
|
||||||
// const scroll = unref(scrollRef);
|
|
||||||
// if (scroll) {
|
|
||||||
// scroll.scrollBottom();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function scrollTo(to: number) {
|
|
||||||
// const scroll = unref(scrollRef);
|
|
||||||
// if (scroll) {
|
|
||||||
// scroll.scrollTo(to);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function getScrollWrap() {
|
|
||||||
// const scroll = unref(scrollRef);
|
|
||||||
// if (scroll) {
|
|
||||||
// return scroll.getScrollWrap();
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// 取消事件
|
// 取消事件
|
||||||
async function onClose(e: any) {
|
async function onClose(e: any) {
|
||||||
const { closeFunc } = unref(getProps);
|
const { closeFunc } = unref(getProps);
|
||||||
@@ -219,12 +186,6 @@ export default defineComponent({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// const currentInstance = getCurrentInstance() as any;
|
|
||||||
// if (getCurrentInstance()) {
|
|
||||||
// currentInstance.scrollBottom = scrollBottom;
|
|
||||||
// currentInstance.scrollTo = scrollTo;
|
|
||||||
// currentInstance.getScrollWrap = getScrollWrap;
|
|
||||||
// }
|
|
||||||
const drawerInstance: DrawerInstance = {
|
const drawerInstance: DrawerInstance = {
|
||||||
setDrawerProps: setDrawerProps,
|
setDrawerProps: setDrawerProps,
|
||||||
};
|
};
|
||||||
@@ -253,15 +214,6 @@ export default defineComponent({
|
|||||||
class={[!unref(getProps).loading ? 'hidden' : '']}
|
class={[!unref(getProps).loading ? 'hidden' : '']}
|
||||||
tip="加载中..."
|
tip="加载中..."
|
||||||
/>
|
/>
|
||||||
{/* <ScrollContainer
|
|
||||||
ref={scrollRef}
|
|
||||||
{...{ ...attrs, ...unref(getScrollOptions) }}
|
|
||||||
style={{
|
|
||||||
height: `calc(100% - ${footerHeight})`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{() => getSlot(slots, 'default')}
|
|
||||||
</ScrollContainer> */}
|
|
||||||
<div
|
<div
|
||||||
ref={scrollRef}
|
ref={scrollRef}
|
||||||
{...attrs}
|
{...attrs}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
export { default as ImportExcel } from './src/ImportExcel';
|
export { default as ImportExcel } from './src/ImportExcel.vue';
|
||||||
export { default as ExportExcelModel } from './src/ExportExcelModel.vue';
|
export { default as ExportExcelModel } from './src/ExportExcelModel.vue';
|
||||||
|
|
||||||
export { jsonToSheetXlsx, aoaToSheetXlsx } from './src/Export2Excel';
|
export { jsonToSheetXlsx, aoaToSheetXlsx } from './src/Export2Excel';
|
||||||
|
@@ -55,12 +55,13 @@
|
|||||||
];
|
];
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { BasicModal, BasicForm },
|
components: { BasicModal, BasicForm },
|
||||||
|
emits: ['success', 'register'],
|
||||||
setup(_, { emit }) {
|
setup(_, { emit }) {
|
||||||
const [registerForm, { validateFields }] = useForm();
|
const [registerForm, { validateFields }] = useForm();
|
||||||
const [registerModal, { closeModal }] = useModalInner();
|
const [registerModal, { closeModal }] = useModalInner();
|
||||||
|
|
||||||
async function handleOk() {
|
async function handleOk() {
|
||||||
const res: ExportModalResult = await validateFields();
|
const res = (await validateFields()) as ExportModalResult;
|
||||||
const { filename, bookType } = res;
|
const { filename, bookType } = res;
|
||||||
|
|
||||||
emit('success', {
|
emit('success', {
|
||||||
@@ -69,6 +70,7 @@
|
|||||||
});
|
});
|
||||||
closeModal();
|
closeModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
schemas,
|
schemas,
|
||||||
handleOk,
|
handleOk,
|
||||||
|
@@ -1,120 +0,0 @@
|
|||||||
import { defineComponent, ref, unref } from 'vue';
|
|
||||||
import XLSX from 'xlsx';
|
|
||||||
import { getSlot } from '/@/utils/helper/tsxHelper';
|
|
||||||
|
|
||||||
import type { ExcelData } from './types';
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'ImportExcel',
|
|
||||||
setup(_, { slots, emit }) {
|
|
||||||
const inputRef = ref<HTMLInputElement | null>(null);
|
|
||||||
const loadingRef = ref<Boolean>(false);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description: 第一行作为头部
|
|
||||||
*/
|
|
||||||
function getHeaderRow(sheet: XLSX.WorkSheet) {
|
|
||||||
if (!sheet || !sheet['!ref']) return [];
|
|
||||||
const headers: string[] = [];
|
|
||||||
// A3:B7=>{s:{c:0, r:2}, e:{c:1, r:6}}
|
|
||||||
const range = XLSX.utils.decode_range(sheet['!ref']);
|
|
||||||
|
|
||||||
const R = range.s.r;
|
|
||||||
/* start in the first row */
|
|
||||||
for (let C = range.s.c; C <= range.e.c; ++C) {
|
|
||||||
/* walk every column in the range */
|
|
||||||
const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })];
|
|
||||||
/* find the cell in the first row */
|
|
||||||
let hdr = 'UNKNOWN ' + C; // <-- replace with your desired default
|
|
||||||
if (cell && cell.t) hdr = XLSX.utils.format_cell(cell);
|
|
||||||
headers.push(hdr);
|
|
||||||
}
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description: 获得excel数据
|
|
||||||
*/
|
|
||||||
function getExcelData(workbook: XLSX.WorkBook) {
|
|
||||||
const excelData: ExcelData[] = [];
|
|
||||||
for (const sheetName of workbook.SheetNames) {
|
|
||||||
const worksheet = workbook.Sheets[sheetName];
|
|
||||||
const header: string[] = getHeaderRow(worksheet);
|
|
||||||
const results = XLSX.utils.sheet_to_json(worksheet);
|
|
||||||
excelData.push({
|
|
||||||
header,
|
|
||||||
results,
|
|
||||||
meta: {
|
|
||||||
sheetName,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return excelData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description: 读取excel数据
|
|
||||||
*/
|
|
||||||
function readerData(rawFile: File) {
|
|
||||||
loadingRef.value = true;
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = async (e) => {
|
|
||||||
try {
|
|
||||||
const data = e.target && e.target.result;
|
|
||||||
const workbook = XLSX.read(data, { type: 'array' });
|
|
||||||
// console.log(workbook);
|
|
||||||
/* DO SOMETHING WITH workbook HERE */
|
|
||||||
const excelData = getExcelData(workbook);
|
|
||||||
emit('success', excelData);
|
|
||||||
resolve();
|
|
||||||
} catch (error) {
|
|
||||||
reject(error);
|
|
||||||
} finally {
|
|
||||||
loadingRef.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
reader.readAsArrayBuffer(rawFile);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function upload(rawFile: File) {
|
|
||||||
const inputRefDom = unref(inputRef);
|
|
||||||
if (inputRefDom) {
|
|
||||||
// fix can't select the same excel
|
|
||||||
inputRefDom.value = '';
|
|
||||||
}
|
|
||||||
readerData(rawFile);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @description: 触发选择文件管理器
|
|
||||||
*/
|
|
||||||
function handleInputClick(e: Event) {
|
|
||||||
const files = e && (e.target as HTMLInputElement).files;
|
|
||||||
const rawFile = files && files[0]; // only use files[0]
|
|
||||||
if (!rawFile) return;
|
|
||||||
upload(rawFile);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @description: 点击上传按钮
|
|
||||||
*/
|
|
||||||
function handleUpload() {
|
|
||||||
const inputRefDom = unref(inputRef);
|
|
||||||
inputRefDom && inputRefDom.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
ref={inputRef}
|
|
||||||
type="file"
|
|
||||||
accept=".xlsx, .xls"
|
|
||||||
style=" z-index: -9999; display: none;"
|
|
||||||
onChange={handleInputClick}
|
|
||||||
/>
|
|
||||||
<div onClick={handleUpload}>{getSlot(slots)}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
123
src/components/Excel/src/ImportExcel.vue
Normal file
123
src/components/Excel/src/ImportExcel.vue
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
ref="inputRef"
|
||||||
|
type="file"
|
||||||
|
v-show="false"
|
||||||
|
accept=".xlsx, .xls"
|
||||||
|
@change="handleInputClick"
|
||||||
|
/>
|
||||||
|
<div @click="handleUpload"><slot /></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref, unref } from 'vue';
|
||||||
|
import XLSX from 'xlsx';
|
||||||
|
|
||||||
|
import type { ExcelData } from './types';
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'ImportExcel',
|
||||||
|
emits: ['success'],
|
||||||
|
setup(_, { emit }) {
|
||||||
|
const inputRef = ref<HTMLInputElement | null>(null);
|
||||||
|
const loadingRef = ref<Boolean>(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 第一行作为头部
|
||||||
|
*/
|
||||||
|
function getHeaderRow(sheet: XLSX.WorkSheet) {
|
||||||
|
if (!sheet || !sheet['!ref']) return [];
|
||||||
|
const headers: string[] = [];
|
||||||
|
// A3:B7=>{s:{c:0, r:2}, e:{c:1, r:6}}
|
||||||
|
const range = XLSX.utils.decode_range(sheet['!ref']);
|
||||||
|
|
||||||
|
const R = range.s.r;
|
||||||
|
/* start in the first row */
|
||||||
|
for (let C = range.s.c; C <= range.e.c; ++C) {
|
||||||
|
/* walk every column in the range */
|
||||||
|
const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })];
|
||||||
|
/* find the cell in the first row */
|
||||||
|
let hdr = 'UNKNOWN ' + C; // <-- replace with your desired default
|
||||||
|
if (cell && cell.t) hdr = XLSX.utils.format_cell(cell);
|
||||||
|
headers.push(hdr);
|
||||||
|
}
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 获得excel数据
|
||||||
|
*/
|
||||||
|
function getExcelData(workbook: XLSX.WorkBook) {
|
||||||
|
const excelData: ExcelData[] = [];
|
||||||
|
for (const sheetName of workbook.SheetNames) {
|
||||||
|
const worksheet = workbook.Sheets[sheetName];
|
||||||
|
const header: string[] = getHeaderRow(worksheet);
|
||||||
|
const results = XLSX.utils.sheet_to_json(worksheet);
|
||||||
|
excelData.push({
|
||||||
|
header,
|
||||||
|
results,
|
||||||
|
meta: {
|
||||||
|
sheetName,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return excelData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 读取excel数据
|
||||||
|
*/
|
||||||
|
function readerData(rawFile: File) {
|
||||||
|
loadingRef.value = true;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = async (e) => {
|
||||||
|
try {
|
||||||
|
const data = e.target && e.target.result;
|
||||||
|
const workbook = XLSX.read(data, { type: 'array' });
|
||||||
|
// console.log(workbook);
|
||||||
|
/* DO SOMETHING WITH workbook HERE */
|
||||||
|
const excelData = getExcelData(workbook);
|
||||||
|
emit('success', excelData);
|
||||||
|
resolve();
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
} finally {
|
||||||
|
loadingRef.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsArrayBuffer(rawFile);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function upload(rawFile: File) {
|
||||||
|
const inputRefDom = unref(inputRef);
|
||||||
|
if (inputRefDom) {
|
||||||
|
// fix can't select the same excel
|
||||||
|
inputRefDom.value = '';
|
||||||
|
}
|
||||||
|
readerData(rawFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 触发选择文件管理器
|
||||||
|
*/
|
||||||
|
function handleInputClick(e: Event) {
|
||||||
|
const files = e && (e.target as HTMLInputElement).files;
|
||||||
|
const rawFile = files && files[0]; // only use files[0]
|
||||||
|
if (!rawFile) return;
|
||||||
|
upload(rawFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 点击上传按钮
|
||||||
|
*/
|
||||||
|
function handleUpload() {
|
||||||
|
const inputRefDom = unref(inputRef);
|
||||||
|
inputRefDom && inputRefDom.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
return { handleUpload, handleInputClick, inputRef };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
@@ -9,7 +9,7 @@ export default {
|
|||||||
component: PAGE_LAYOUT_COMPONENT,
|
component: PAGE_LAYOUT_COMPONENT,
|
||||||
redirect: '/excel/customExport',
|
redirect: '/excel/customExport',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'ant-design:area-chart-outlined',
|
icon: 'mdi:microsoft-excel',
|
||||||
title: 'Excel',
|
title: 'Excel',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -18,7 +18,7 @@ export default {
|
|||||||
{
|
{
|
||||||
path: '/customExport',
|
path: '/customExport',
|
||||||
name: 'CustomExport',
|
name: 'CustomExport',
|
||||||
component: () => import('/@/views/demo/echarts/excel/CustomExport.vue'),
|
component: () => import('/@/views/demo/excel/CustomExport.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: '选择导出格式',
|
title: '选择导出格式',
|
||||||
},
|
},
|
||||||
@@ -26,7 +26,7 @@ export default {
|
|||||||
{
|
{
|
||||||
path: '/jsonExport',
|
path: '/jsonExport',
|
||||||
name: 'JsonExport',
|
name: 'JsonExport',
|
||||||
component: () => import('/@/views/demo/echarts/excel/JsonExport.vue'),
|
component: () => import('/@/views/demo/excel/JsonExport.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'JSON数据导出',
|
title: 'JSON数据导出',
|
||||||
},
|
},
|
||||||
@@ -34,7 +34,7 @@ export default {
|
|||||||
{
|
{
|
||||||
path: '/arrayExport',
|
path: '/arrayExport',
|
||||||
name: 'ArrayExport',
|
name: 'ArrayExport',
|
||||||
component: () => import('/@/views/demo/echarts/excel/ArrayExport.vue'),
|
component: () => import('/@/views/demo/excel/ArrayExport.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'Array数据导出',
|
title: 'Array数据导出',
|
||||||
},
|
},
|
||||||
@@ -42,12 +42,10 @@ export default {
|
|||||||
{
|
{
|
||||||
path: '/importExcel',
|
path: '/importExcel',
|
||||||
name: 'ImportExcel',
|
name: 'ImportExcel',
|
||||||
component: () => import('/@/views/demo/echarts/excel/ImportExcel.vue'),
|
component: () => import('/@/views/demo/excel/ImportExcel.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: '导入',
|
title: '导入',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
],
|
],
|
||||||
} as AppRouteModule;
|
} as AppRouteModule;
|
||||||
|
@@ -9,7 +9,7 @@ export default {
|
|||||||
component: PAGE_LAYOUT_COMPONENT,
|
component: PAGE_LAYOUT_COMPONENT,
|
||||||
redirect: '/tree/basic',
|
redirect: '/tree/basic',
|
||||||
meta: {
|
meta: {
|
||||||
icon: 'ant-design:table-outlined',
|
icon: 'clarity:tree-view-line',
|
||||||
title: 'Tree',
|
title: 'Tree',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user