精简代码,删除几个非必须依赖xlsx、fullcalendar、lodash.get、lodash.pick等
parent
5aec20bfa0
commit
9f83a9ea29
21
package.json
21
package.json
|
@ -36,12 +36,6 @@
|
|||
"dependencies": {
|
||||
"@jeecg/online": "1.0.1",
|
||||
"@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",
|
||||
"@zxcvbn-ts/core": "^1.0.0-beta.0",
|
||||
"ant-design-vue": "2.2.8",
|
||||
|
@ -59,8 +53,6 @@
|
|||
"intro.js": "^4.2.2",
|
||||
"js-cookie": "^2.2.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.pick": "^4.4.0",
|
||||
"md5": "^2.3.0",
|
||||
"mockjs": "^1.1.0",
|
||||
"nprogress": "^0.2.0",
|
||||
|
@ -87,7 +79,6 @@
|
|||
"vxe-table": "4.1.0",
|
||||
"vxe-table-plugin-antd": "^3.0.3",
|
||||
"xe-utils": "^3.3.1",
|
||||
"xlsx": "^0.17.3",
|
||||
"vue-json-pretty": "^2.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -188,11 +179,6 @@
|
|||
"include": [
|
||||
"@ant-design/colors",
|
||||
"@ant-design/icons-vue",
|
||||
"@fullcalendar/core/vdom",
|
||||
"@fullcalendar/daygrid",
|
||||
"@fullcalendar/interaction",
|
||||
"@fullcalendar/timegrid",
|
||||
"@fullcalendar/vue3",
|
||||
"@jeecg/online",
|
||||
"@vueuse/core",
|
||||
"@vueuse/shared",
|
||||
|
@ -211,7 +197,10 @@
|
|||
"codemirror/addon/hint/show-hint.js",
|
||||
"codemirror/addon/selection/active-line.js",
|
||||
"codemirror/mode/clike/clike.js",
|
||||
"codemirror/mode/css/css",
|
||||
"codemirror/mode/css/css.js",
|
||||
"codemirror/mode/htmlmixed/htmlmixed",
|
||||
"codemirror/mode/javascript/javascript",
|
||||
"codemirror/mode/javascript/javascript.js",
|
||||
"codemirror/mode/markdown/markdown.js",
|
||||
"codemirror/mode/python/python.js",
|
||||
|
@ -289,14 +278,14 @@
|
|||
"vite-plugin-theme/es/colorUtils",
|
||||
"vue",
|
||||
"vue-i18n",
|
||||
"vue-json-pretty",
|
||||
"vue-print-nb-jeecg/src/printarea",
|
||||
"vue-router",
|
||||
"vue-types",
|
||||
"vuedraggable",
|
||||
"vxe-table",
|
||||
"vxe-table-plugin-antd",
|
||||
"xe-utils",
|
||||
"xlsx"
|
||||
"xe-utils"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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'),
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'fullCalendar',
|
||||
name: 'fullCalendarDemo',
|
||||
component: () => import('/@/views/demo/fullcalendar/index.vue'),
|
||||
meta: {
|
||||
title: t('routes.demo.feat.fullCalendar'),
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'codemirror',
|
||||
name: 'codemirrorDemo',
|
||||
|
|
|
@ -129,51 +129,6 @@ const feat: AppRouteModule = {
|
|||
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',
|
||||
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