精简代码,删除几个非必须依赖xlsx、fullcalendar、lodash.get、lodash.pick等
This commit is contained in:
parent
5aec20bfa0
commit
9f83a9ea29
21
package.json
21
package.json
|
@ -36,12 +36,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jeecg/online": "1.0.1",
|
"@jeecg/online": "1.0.1",
|
||||||
"@iconify/iconify": "^2.0.4",
|
"@iconify/iconify": "^2.0.4",
|
||||||
"@fullcalendar/core": "5.10.1",
|
|
||||||
"@fullcalendar/daygrid": "5.10.1",
|
|
||||||
"@fullcalendar/interaction": "5.10.1",
|
|
||||||
"@fullcalendar/resource-timeline": "5.10.1",
|
|
||||||
"@fullcalendar/timegrid": "5.10.1",
|
|
||||||
"@fullcalendar/vue3": "5.10.1",
|
|
||||||
"@vueuse/core": "^6.6.2",
|
"@vueuse/core": "^6.6.2",
|
||||||
"@zxcvbn-ts/core": "^1.0.0-beta.0",
|
"@zxcvbn-ts/core": "^1.0.0-beta.0",
|
||||||
"ant-design-vue": "2.2.8",
|
"ant-design-vue": "2.2.8",
|
||||||
|
@ -59,8 +53,6 @@
|
||||||
"intro.js": "^4.2.2",
|
"intro.js": "^4.2.2",
|
||||||
"js-cookie": "^2.2.1",
|
"js-cookie": "^2.2.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"lodash.get": "^4.4.2",
|
|
||||||
"lodash.pick": "^4.4.0",
|
|
||||||
"md5": "^2.3.0",
|
"md5": "^2.3.0",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
|
@ -87,7 +79,6 @@
|
||||||
"vxe-table": "4.1.0",
|
"vxe-table": "4.1.0",
|
||||||
"vxe-table-plugin-antd": "^3.0.3",
|
"vxe-table-plugin-antd": "^3.0.3",
|
||||||
"xe-utils": "^3.3.1",
|
"xe-utils": "^3.3.1",
|
||||||
"xlsx": "^0.17.3",
|
|
||||||
"vue-json-pretty": "^2.0.4"
|
"vue-json-pretty": "^2.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -188,11 +179,6 @@
|
||||||
"include": [
|
"include": [
|
||||||
"@ant-design/colors",
|
"@ant-design/colors",
|
||||||
"@ant-design/icons-vue",
|
"@ant-design/icons-vue",
|
||||||
"@fullcalendar/core/vdom",
|
|
||||||
"@fullcalendar/daygrid",
|
|
||||||
"@fullcalendar/interaction",
|
|
||||||
"@fullcalendar/timegrid",
|
|
||||||
"@fullcalendar/vue3",
|
|
||||||
"@jeecg/online",
|
"@jeecg/online",
|
||||||
"@vueuse/core",
|
"@vueuse/core",
|
||||||
"@vueuse/shared",
|
"@vueuse/shared",
|
||||||
|
@ -211,7 +197,10 @@
|
||||||
"codemirror/addon/hint/show-hint.js",
|
"codemirror/addon/hint/show-hint.js",
|
||||||
"codemirror/addon/selection/active-line.js",
|
"codemirror/addon/selection/active-line.js",
|
||||||
"codemirror/mode/clike/clike.js",
|
"codemirror/mode/clike/clike.js",
|
||||||
|
"codemirror/mode/css/css",
|
||||||
"codemirror/mode/css/css.js",
|
"codemirror/mode/css/css.js",
|
||||||
|
"codemirror/mode/htmlmixed/htmlmixed",
|
||||||
|
"codemirror/mode/javascript/javascript",
|
||||||
"codemirror/mode/javascript/javascript.js",
|
"codemirror/mode/javascript/javascript.js",
|
||||||
"codemirror/mode/markdown/markdown.js",
|
"codemirror/mode/markdown/markdown.js",
|
||||||
"codemirror/mode/python/python.js",
|
"codemirror/mode/python/python.js",
|
||||||
|
@ -289,14 +278,14 @@
|
||||||
"vite-plugin-theme/es/colorUtils",
|
"vite-plugin-theme/es/colorUtils",
|
||||||
"vue",
|
"vue",
|
||||||
"vue-i18n",
|
"vue-i18n",
|
||||||
|
"vue-json-pretty",
|
||||||
"vue-print-nb-jeecg/src/printarea",
|
"vue-print-nb-jeecg/src/printarea",
|
||||||
"vue-router",
|
"vue-router",
|
||||||
"vue-types",
|
"vue-types",
|
||||||
"vuedraggable",
|
"vuedraggable",
|
||||||
"vxe-table",
|
"vxe-table",
|
||||||
"vxe-table-plugin-antd",
|
"vxe-table-plugin-antd",
|
||||||
"xe-utils",
|
"xe-utils"
|
||||||
"xlsx"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
import { withInstall } from '/@/utils';
|
|
||||||
import impExcel from './src/ImportExcel.vue';
|
|
||||||
import expExcelModal from './src/ExportExcelModal.vue';
|
|
||||||
|
|
||||||
export const ImpExcel = withInstall(impExcel);
|
|
||||||
export const ExpExcelModal = withInstall(expExcelModal);
|
|
||||||
export * from './src/typing';
|
|
||||||
export { jsonToSheetXlsx, aoaToSheetXlsx } from './src/Export2Excel';
|
|
|
@ -1,48 +0,0 @@
|
||||||
import xlsx from 'xlsx';
|
|
||||||
import type { WorkBook } from 'xlsx';
|
|
||||||
import type { JsonToSheet, AoAToSheet } from './typing';
|
|
||||||
|
|
||||||
const { utils, writeFile } = xlsx;
|
|
||||||
|
|
||||||
const DEF_FILE_NAME = 'excel-list.xlsx';
|
|
||||||
|
|
||||||
export function jsonToSheetXlsx<T = any>({ data, header, filename = DEF_FILE_NAME, json2sheetOpts = {}, write2excelOpts = { bookType: 'xlsx' } }: JsonToSheet<T>) {
|
|
||||||
const arrData = [...data];
|
|
||||||
if (header) {
|
|
||||||
arrData.unshift(header);
|
|
||||||
json2sheetOpts.skipHeader = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const worksheet = utils.json_to_sheet(arrData, json2sheetOpts);
|
|
||||||
|
|
||||||
/* add worksheet to workbook */
|
|
||||||
const workbook: WorkBook = {
|
|
||||||
SheetNames: [filename],
|
|
||||||
Sheets: {
|
|
||||||
[filename]: worksheet,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
/* output format determined by filename */
|
|
||||||
writeFile(workbook, filename, write2excelOpts);
|
|
||||||
/* at this point, out.xlsb will have been downloaded */
|
|
||||||
}
|
|
||||||
|
|
||||||
export function aoaToSheetXlsx<T = any>({ data, header, filename = DEF_FILE_NAME, write2excelOpts = { bookType: 'xlsx' } }: AoAToSheet<T>) {
|
|
||||||
const arrData = [...data];
|
|
||||||
if (header) {
|
|
||||||
arrData.unshift(header);
|
|
||||||
}
|
|
||||||
|
|
||||||
const worksheet = utils.aoa_to_sheet(arrData);
|
|
||||||
|
|
||||||
/* add worksheet to workbook */
|
|
||||||
const workbook: WorkBook = {
|
|
||||||
SheetNames: [filename],
|
|
||||||
Sheets: {
|
|
||||||
[filename]: worksheet,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
/* output format determined by filename */
|
|
||||||
writeFile(workbook, filename, write2excelOpts);
|
|
||||||
/* at this point, out.xlsb will have been downloaded */
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
<template>
|
|
||||||
<BasicModal v-bind="$attrs" :title="t('component.excel.exportModalTitle')" @ok="handleOk" @register="registerModal">
|
|
||||||
<BasicForm :labelWidth="100" :schemas="schemas" :showActionButtonGroup="false" @register="registerForm" />
|
|
||||||
</BasicModal>
|
|
||||||
</template>
|
|
||||||
<script lang="ts">
|
|
||||||
import type { ExportModalResult } from './typing';
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
|
||||||
import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
|
|
||||||
|
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const schemas: FormSchema[] = [
|
|
||||||
{
|
|
||||||
field: 'filename',
|
|
||||||
component: 'Input',
|
|
||||||
label: t('component.excel.fileName'),
|
|
||||||
rules: [{ required: true }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: 'bookType',
|
|
||||||
component: 'Select',
|
|
||||||
label: t('component.excel.fileType'),
|
|
||||||
defaultValue: 'xlsx',
|
|
||||||
rules: [{ required: true }],
|
|
||||||
componentProps: {
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: 'xlsx',
|
|
||||||
value: 'xlsx',
|
|
||||||
key: 'xlsx',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'html',
|
|
||||||
value: 'html',
|
|
||||||
key: 'html',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'csv',
|
|
||||||
value: 'csv',
|
|
||||||
key: 'csv',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'txt',
|
|
||||||
value: 'txt',
|
|
||||||
key: 'txt',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
export default defineComponent({
|
|
||||||
components: { BasicModal, BasicForm },
|
|
||||||
emits: ['success', 'register'],
|
|
||||||
setup(_, { emit }) {
|
|
||||||
const [registerForm, { validateFields }] = useForm();
|
|
||||||
const [registerModal, { closeModal }] = useModalInner();
|
|
||||||
|
|
||||||
async function handleOk() {
|
|
||||||
const res = (await validateFields()) as ExportModalResult;
|
|
||||||
const { filename, bookType } = res;
|
|
||||||
emit('success', {
|
|
||||||
filename: `${filename.split('.').shift()}.${bookType}`,
|
|
||||||
bookType,
|
|
||||||
});
|
|
||||||
closeModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
schemas,
|
|
||||||
handleOk,
|
|
||||||
registerForm,
|
|
||||||
registerModal,
|
|
||||||
t,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
|
@ -1,151 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<input ref="inputRef" type="file" v-show="false" accept=".xlsx, .xls" @change="handleInputClick" />
|
|
||||||
<div @click="handleUpload">
|
|
||||||
<slot></slot>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, ref, unref } from 'vue';
|
|
||||||
import XLSX from 'xlsx';
|
|
||||||
import { dateUtil } from '/@/utils/dateUtil';
|
|
||||||
|
|
||||||
import type { ExcelData } from './typing';
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'ImportExcel',
|
|
||||||
props: {
|
|
||||||
// 日期时间格式。如果不提供或者提供空值,将返回原始Date对象
|
|
||||||
dateFormat: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
// 时区调整。实验性功能,仅为了解决读取日期时间值有偏差的问题。目前仅提供了+08:00时区的偏差修正值
|
|
||||||
// https://github.com/SheetJS/sheetjs/issues/1470#issuecomment-501108554
|
|
||||||
timeZone: {
|
|
||||||
type: Number,
|
|
||||||
default: 8,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: ['success', 'error'],
|
|
||||||
setup(props, { 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[] = [];
|
|
||||||
const { dateFormat, timeZone } = props;
|
|
||||||
for (const sheetName of workbook.SheetNames) {
|
|
||||||
const worksheet = workbook.Sheets[sheetName];
|
|
||||||
const header: string[] = getHeaderRow(worksheet);
|
|
||||||
let results = XLSX.utils.sheet_to_json(worksheet, {
|
|
||||||
raw: true,
|
|
||||||
dateNF: dateFormat, //Not worked
|
|
||||||
}) as object[];
|
|
||||||
results = results.map((row: object) => {
|
|
||||||
for (let field in row) {
|
|
||||||
if (row[field] instanceof Date) {
|
|
||||||
if (timeZone === 8) {
|
|
||||||
row[field].setSeconds(row[field].getSeconds() + 43);
|
|
||||||
}
|
|
||||||
if (dateFormat) {
|
|
||||||
row[field] = dateUtil(row[field]).format(dateFormat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return row;
|
|
||||||
});
|
|
||||||
|
|
||||||
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', cellDates: true });
|
|
||||||
// console.log(workbook);
|
|
||||||
/* DO SOMETHING WITH workbook HERE */
|
|
||||||
const excelData = getExcelData(workbook);
|
|
||||||
emit('success', excelData);
|
|
||||||
resolve('');
|
|
||||||
} catch (error) {
|
|
||||||
reject(error);
|
|
||||||
emit('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 = '';
|
|
||||||
}
|
|
||||||
await readerData(rawFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description: 触发选择文件管理器
|
|
||||||
*/
|
|
||||||
function handleInputClick(e: Event) {
|
|
||||||
const files = e && (e.target as HTMLInputElement).files;
|
|
||||||
const rawFile = files && files[0]; // only setting files[0]
|
|
||||||
if (!rawFile) return;
|
|
||||||
upload(rawFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description: 点击上传按钮
|
|
||||||
*/
|
|
||||||
function handleUpload() {
|
|
||||||
const inputRefDom = unref(inputRef);
|
|
||||||
inputRefDom && inputRefDom.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
return { handleUpload, handleInputClick, inputRef };
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
|
@ -1,27 +0,0 @@
|
||||||
import type { JSON2SheetOpts, WritingOptions, BookType } from 'xlsx';
|
|
||||||
|
|
||||||
export interface ExcelData<T = any> {
|
|
||||||
header: string[];
|
|
||||||
results: T[];
|
|
||||||
meta: { sheetName: string };
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface JsonToSheet<T = any> {
|
|
||||||
data: T[];
|
|
||||||
header?: T;
|
|
||||||
filename?: string;
|
|
||||||
json2sheetOpts?: JSON2SheetOpts;
|
|
||||||
write2excelOpts?: WritingOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AoAToSheet<T = any> {
|
|
||||||
data: T[][];
|
|
||||||
header?: T[];
|
|
||||||
filename?: string;
|
|
||||||
write2excelOpts?: WritingOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExportModalResult {
|
|
||||||
filename: string;
|
|
||||||
bookType: BookType;
|
|
||||||
}
|
|
|
@ -466,14 +466,6 @@ const comp: AppRouteModule = {
|
||||||
title: t('routes.demo.feat.copy'),
|
title: t('routes.demo.feat.copy'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'fullCalendar',
|
|
||||||
name: 'fullCalendarDemo',
|
|
||||||
component: () => import('/@/views/demo/fullcalendar/index.vue'),
|
|
||||||
meta: {
|
|
||||||
title: t('routes.demo.feat.fullCalendar'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'codemirror',
|
path: 'codemirror',
|
||||||
name: 'codemirrorDemo',
|
name: 'codemirrorDemo',
|
||||||
|
|
|
@ -129,51 +129,6 @@ const feat: AppRouteModule = {
|
||||||
title: t('routes.demo.feat.errorLog'),
|
title: t('routes.demo.feat.errorLog'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'excel',
|
|
||||||
name: 'Excel',
|
|
||||||
redirect: '/feat/excel/customExport',
|
|
||||||
component: getParentLayout('Excel'),
|
|
||||||
meta: {
|
|
||||||
// icon: 'mdi:microsoft-excel',
|
|
||||||
title: t('routes.demo.excel.excel'),
|
|
||||||
},
|
|
||||||
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'customExport',
|
|
||||||
name: 'CustomExport',
|
|
||||||
component: () => import('/@/views/demo/excel/CustomExport.vue'),
|
|
||||||
meta: {
|
|
||||||
title: t('routes.demo.excel.customExport'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'jsonExport',
|
|
||||||
name: 'JsonExport',
|
|
||||||
component: () => import('/@/views/demo/excel/JsonExport.vue'),
|
|
||||||
meta: {
|
|
||||||
title: t('routes.demo.excel.jsonExport'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'arrayExport',
|
|
||||||
name: 'ArrayExport',
|
|
||||||
component: () => import('/@/views/demo/excel/ArrayExport.vue'),
|
|
||||||
meta: {
|
|
||||||
title: t('routes.demo.excel.arrayExport'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'importExcel',
|
|
||||||
name: 'ImportExcel',
|
|
||||||
component: () => import('/@/views/demo/excel/ImportExcel.vue'),
|
|
||||||
meta: {
|
|
||||||
title: t('routes.demo.excel.importExcel'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'testTab/:id',
|
path: 'testTab/:id',
|
||||||
name: 'TestTab',
|
name: 'TestTab',
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
<template>
|
|
||||||
<PageWrapper title="导出示例" content="根据数组格式的数据进行导出">
|
|
||||||
<BasicTable title="基础表格" :columns="columns" :dataSource="data">
|
|
||||||
<template #toolbar>
|
|
||||||
<a-button @click="aoaToExcel"> 导出 </a-button>
|
|
||||||
</template>
|
|
||||||
</BasicTable>
|
|
||||||
</PageWrapper>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { BasicTable } from '/@/components/Table';
|
|
||||||
import { aoaToSheetXlsx } from '/@/components/Excel';
|
|
||||||
import { arrHeader, arrData, columns, data } from './data';
|
|
||||||
import { PageWrapper } from '/@/components/Page';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: { BasicTable, PageWrapper },
|
|
||||||
setup() {
|
|
||||||
function aoaToExcel() {
|
|
||||||
// 保证data顺序与header一致
|
|
||||||
aoaToSheetXlsx({
|
|
||||||
data: arrData,
|
|
||||||
header: arrHeader,
|
|
||||||
filename: '二维数组方式导出excel.xlsx',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
aoaToExcel,
|
|
||||||
columns,
|
|
||||||
data,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
|
@ -1,44 +0,0 @@
|
||||||
<template>
|
|
||||||
<PageWrapper title="导出示例" content="可以选择导出格式">
|
|
||||||
<BasicTable title="基础表格" :columns="columns" :dataSource="data">
|
|
||||||
<template #toolbar>
|
|
||||||
<a-button @click="openModal"> 导出 </a-button>
|
|
||||||
</template>
|
|
||||||
</BasicTable>
|
|
||||||
<ExpExcelModal @register="register" @success="defaultHeader" />
|
|
||||||
</PageWrapper>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { BasicTable } from '/@/components/Table';
|
|
||||||
import { jsonToSheetXlsx, ExpExcelModal, ExportModalResult } from '/@/components/Excel';
|
|
||||||
import { columns, data } from './data';
|
|
||||||
import { useModal } from '/@/components/Modal';
|
|
||||||
import { PageWrapper } from '/@/components/Page';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: { BasicTable, ExpExcelModal, PageWrapper },
|
|
||||||
setup() {
|
|
||||||
function defaultHeader({ filename, bookType }: ExportModalResult) {
|
|
||||||
// 默认Object.keys(data[0])作为header
|
|
||||||
jsonToSheetXlsx({
|
|
||||||
data,
|
|
||||||
filename,
|
|
||||||
write2excelOpts: {
|
|
||||||
bookType,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const [register, { openModal }] = useModal();
|
|
||||||
|
|
||||||
return {
|
|
||||||
defaultHeader,
|
|
||||||
columns,
|
|
||||||
data,
|
|
||||||
register,
|
|
||||||
openModal,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
|
@ -1,51 +0,0 @@
|
||||||
<template>
|
|
||||||
<PageWrapper title="excel数据导入示例">
|
|
||||||
<ImpExcel @success="loadDataSuccess" dateFormat="YYYY-MM-DD">
|
|
||||||
<a-button class="m-3"> 导入Excel </a-button>
|
|
||||||
</ImpExcel>
|
|
||||||
<BasicTable v-for="(table, index) in tableListRef" :key="index" :title="table.title" :columns="table.columns" :dataSource="table.dataSource" />
|
|
||||||
</PageWrapper>
|
|
||||||
</template>
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, ref } from 'vue';
|
|
||||||
|
|
||||||
import { ImpExcel, ExcelData } from '/@/components/Excel';
|
|
||||||
import { BasicTable, BasicColumn } from '/@/components/Table';
|
|
||||||
import { PageWrapper } from '/@/components/Page';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: { BasicTable, ImpExcel, PageWrapper },
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const tableListRef = ref<
|
|
||||||
{
|
|
||||||
title: string;
|
|
||||||
columns?: any[];
|
|
||||||
dataSource?: any[];
|
|
||||||
}[]
|
|
||||||
>([]);
|
|
||||||
|
|
||||||
function loadDataSuccess(excelDataList: ExcelData[]) {
|
|
||||||
tableListRef.value = [];
|
|
||||||
console.log(excelDataList);
|
|
||||||
for (const excelData of excelDataList) {
|
|
||||||
const {
|
|
||||||
header,
|
|
||||||
results,
|
|
||||||
meta: { sheetName },
|
|
||||||
} = excelData;
|
|
||||||
const columns: BasicColumn[] = [];
|
|
||||||
for (const title of header) {
|
|
||||||
columns.push({ title, dataIndex: title });
|
|
||||||
}
|
|
||||||
tableListRef.value.push({ title: sheetName, dataSource: results, columns });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
loadDataSuccess,
|
|
||||||
tableListRef,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
|
@ -1,58 +0,0 @@
|
||||||
<template>
|
|
||||||
<PageWrapper title="导出示例" content="根据JSON格式的数据进行导出">
|
|
||||||
<BasicTable title="基础表格" :columns="columns" :dataSource="data">
|
|
||||||
<template #toolbar>
|
|
||||||
<a-button @click="defaultHeader"> 导出:默认头部 </a-button>
|
|
||||||
<a-button @click="customHeader"> 导出:自定义头部 </a-button>
|
|
||||||
</template>
|
|
||||||
</BasicTable>
|
|
||||||
</PageWrapper>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { BasicTable } from '/@/components/Table';
|
|
||||||
import { jsonToSheetXlsx } from '/@/components/Excel';
|
|
||||||
import { columns, data } from './data';
|
|
||||||
import { PageWrapper } from '/@/components/Page';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: { BasicTable, PageWrapper },
|
|
||||||
setup() {
|
|
||||||
function defaultHeader() {
|
|
||||||
// 默认Object.keys(data[0])作为header
|
|
||||||
jsonToSheetXlsx({
|
|
||||||
data,
|
|
||||||
filename: '使用key作为默认头部.xlsx',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function customHeader() {
|
|
||||||
jsonToSheetXlsx({
|
|
||||||
data,
|
|
||||||
header: {
|
|
||||||
id: 'ID',
|
|
||||||
name: '姓名',
|
|
||||||
age: '年龄',
|
|
||||||
no: '编号',
|
|
||||||
address: '地址',
|
|
||||||
beginTime: '开始时间',
|
|
||||||
endTime: '结束时间',
|
|
||||||
},
|
|
||||||
filename: '自定义头部.xlsx',
|
|
||||||
json2sheetOpts: {
|
|
||||||
// 指定顺序
|
|
||||||
header: ['name', 'id'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
defaultHeader,
|
|
||||||
customHeader,
|
|
||||||
columns,
|
|
||||||
data,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
|
@ -1,59 +0,0 @@
|
||||||
import { BasicColumn } from '/@/components/Table';
|
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [
|
|
||||||
{
|
|
||||||
title: 'ID',
|
|
||||||
dataIndex: 'id',
|
|
||||||
width: 80,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '姓名',
|
|
||||||
dataIndex: 'name',
|
|
||||||
width: 120,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '年龄',
|
|
||||||
dataIndex: 'age',
|
|
||||||
width: 80,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '编号',
|
|
||||||
dataIndex: 'no',
|
|
||||||
width: 80,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '地址',
|
|
||||||
dataIndex: 'address',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '开始时间',
|
|
||||||
dataIndex: 'beginTime',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '结束时间',
|
|
||||||
dataIndex: 'endTime',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const data: any[] = (() => {
|
|
||||||
const arr: any[] = [];
|
|
||||||
for (let index = 0; index < 40; index++) {
|
|
||||||
arr.push({
|
|
||||||
id: `${index}`,
|
|
||||||
name: `${index} John Brown`,
|
|
||||||
age: `${index + 10}`,
|
|
||||||
no: `${index}98678`,
|
|
||||||
address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park',
|
|
||||||
beginTime: new Date().toLocaleString(),
|
|
||||||
endTime: new Date().toLocaleString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
})();
|
|
||||||
|
|
||||||
// ["ID", "姓名", "年龄", "编号", "地址", "开始时间", "结束时间"]
|
|
||||||
export const arrHeader = columns.map((column) => column.title);
|
|
||||||
// [["ID", "姓名", "年龄", "编号", "地址", "开始时间", "结束时间"],["0", "0 John Brown", "10", "098678"]]
|
|
||||||
export const arrData = data.map((item) => {
|
|
||||||
return Object.keys(item).map((key) => item[key]);
|
|
||||||
});
|
|
|
@ -1,21 +0,0 @@
|
||||||
import { EventInput } from '@fullcalendar/vue3';
|
|
||||||
|
|
||||||
let eventGuid = 0;
|
|
||||||
let todayStr = new Date().toISOString().replace(/T.*$/, ''); // YYYY-MM-DD of today
|
|
||||||
|
|
||||||
export const INITIAL_EVENTS: EventInput[] = [
|
|
||||||
{
|
|
||||||
id: createEventId(),
|
|
||||||
title: 'All-day event',
|
|
||||||
start: todayStr,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: createEventId(),
|
|
||||||
title: 'Timed event',
|
|
||||||
start: todayStr + 'T12:00:00',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export function createEventId() {
|
|
||||||
return String(eventGuid++);
|
|
||||||
}
|
|
|
@ -1,166 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import '@fullcalendar/core/vdom'; // solve problem with Vite
|
|
||||||
import FullCalendar, { CalendarOptions, EventApi, DateSelectArg, EventClickArg } from '@fullcalendar/vue3';
|
|
||||||
import dayGridPlugin from '@fullcalendar/daygrid';
|
|
||||||
import timeGridPlugin from '@fullcalendar/timegrid';
|
|
||||||
import interactionPlugin from '@fullcalendar/interaction';
|
|
||||||
import { INITIAL_EVENTS, createEventId } from './event-utils';
|
|
||||||
|
|
||||||
const Demo = defineComponent({
|
|
||||||
components: {
|
|
||||||
FullCalendar,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
calendarOptions: {
|
|
||||||
plugins: [
|
|
||||||
dayGridPlugin,
|
|
||||||
timeGridPlugin,
|
|
||||||
interactionPlugin, // needed for dateClick
|
|
||||||
],
|
|
||||||
headerToolbar: {
|
|
||||||
left: 'prev,next today',
|
|
||||||
center: 'title',
|
|
||||||
right: 'dayGridMonth,timeGridWeek,timeGridDay',
|
|
||||||
},
|
|
||||||
initialView: 'dayGridMonth',
|
|
||||||
initialEvents: INITIAL_EVENTS, // alternatively, use the `events` setting to fetch from a feed
|
|
||||||
editable: true,
|
|
||||||
selectable: true,
|
|
||||||
selectMirror: true,
|
|
||||||
dayMaxEvents: true,
|
|
||||||
weekends: true,
|
|
||||||
select: this.handleDateSelect,
|
|
||||||
eventClick: this.handleEventClick,
|
|
||||||
eventsSet: this.handleEvents,
|
|
||||||
/* you can update a remote database when these fire:
|
|
||||||
eventAdd:
|
|
||||||
eventChange:
|
|
||||||
eventRemove:
|
|
||||||
*/
|
|
||||||
} as CalendarOptions,
|
|
||||||
currentEvents: [] as EventApi[],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleWeekendsToggle() {
|
|
||||||
this.calendarOptions.weekends = !this.calendarOptions.weekends; // update a property
|
|
||||||
},
|
|
||||||
handleDateSelect(selectInfo: DateSelectArg) {
|
|
||||||
let title = prompt('Please enter a new title for your event');
|
|
||||||
let calendarApi = selectInfo.view.calendar;
|
|
||||||
|
|
||||||
calendarApi.unselect(); // clear date selection
|
|
||||||
|
|
||||||
if (title) {
|
|
||||||
calendarApi.addEvent({
|
|
||||||
id: createEventId(),
|
|
||||||
title,
|
|
||||||
start: selectInfo.startStr,
|
|
||||||
end: selectInfo.endStr,
|
|
||||||
allDay: selectInfo.allDay,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleEventClick(clickInfo: EventClickArg) {
|
|
||||||
if (confirm(`Are you sure you want to delete the event '${clickInfo.event.title}'`)) {
|
|
||||||
clickInfo.event.remove();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleEvents(events: EventApi[]) {
|
|
||||||
this.currentEvents = events;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
export default Demo;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="demo-app">
|
|
||||||
<div class="demo-app-sidebar">
|
|
||||||
<div class="demo-app-sidebar-section">
|
|
||||||
<h2>Instructions</h2>
|
|
||||||
<ul>
|
|
||||||
<li>Select dates and you will be prompted to create a new event</li>
|
|
||||||
<li>Drag, drop, and resize events</li>
|
|
||||||
<li>Click an event to delete it</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="demo-app-sidebar-section">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" :checked="calendarOptions.weekends" @change="handleWeekendsToggle" />
|
|
||||||
toggle weekends
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="demo-app-sidebar-section">
|
|
||||||
<h2>All Events ({{ currentEvents.length }})</h2>
|
|
||||||
<ul>
|
|
||||||
<li v-for="event in currentEvents" :key="event.id">
|
|
||||||
<b>{{ event.startStr }}</b>
|
|
||||||
<i>{{ event.title }}</i>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="demo-app-main">
|
|
||||||
<FullCalendar class="demo-app-calendar" :options="calendarOptions">
|
|
||||||
<template v-slot:eventContent="arg">
|
|
||||||
<b>{{ arg.timeText }}</b>
|
|
||||||
<i>{{ arg.event.title }}</i>
|
|
||||||
</template>
|
|
||||||
</FullCalendar>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="css" scoped>
|
|
||||||
h2 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0 0 0 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin: 1.5em 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
b {
|
|
||||||
/* used for event dates/times */
|
|
||||||
margin-right: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-app {
|
|
||||||
display: flex;
|
|
||||||
min-height: 100%;
|
|
||||||
font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-app-sidebar {
|
|
||||||
width: 300px;
|
|
||||||
line-height: 1.5;
|
|
||||||
background: #eaf9ff;
|
|
||||||
border-right: 1px solid #d3e2e8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-app-sidebar-section {
|
|
||||||
padding: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-app-main {
|
|
||||||
flex-grow: 1;
|
|
||||||
padding: 3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc {
|
|
||||||
/* the calendar root */
|
|
||||||
max-width: 1100px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
Loading…
Reference in New Issue