forked from sheetjs/sheetjs
vue-modify demo [ci skip]
This commit is contained in:
parent
9a3294c955
commit
2cbc28d6ed
24
demos/vue-modify/.gitignore
vendored
Normal file
24
demos/vue-modify/.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
10
demos/vue-modify/README.md
Normal file
10
demos/vue-modify/README.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# vue-modify
|
||||||
|
|
||||||
|
This demo shows import an export with `vue3-table-light` table component.
|
||||||
|
|
||||||
|
In this directory, run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm i
|
||||||
|
npm run dev
|
||||||
|
```
|
21
demos/vue-modify/package.json
Normal file
21
demos/vue-modify/package.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "vue-modify",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite --host",
|
||||||
|
"build": "vue-tsc --noEmit && vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"vue": "^3.2.25",
|
||||||
|
"vue3-table-lite": "^1.1.7-1",
|
||||||
|
"xlsx": "^0.18.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "^2.2.0",
|
||||||
|
"typescript": "^4.5.4",
|
||||||
|
"vite": "^2.8.0",
|
||||||
|
"vue-tsc": "^0.29.8"
|
||||||
|
}
|
||||||
|
}
|
241
demos/vue-modify/src/App.vue
Normal file
241
demos/vue-modify/src/App.vue
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { read, utils, writeFile, WorkBook } from "xlsx";
|
||||||
|
|
||||||
|
import VueTableLite from "vue3-table-lite/ts";
|
||||||
|
|
||||||
|
type DataSet = {
|
||||||
|
[index: string]: WorkBook;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Row = any[];
|
||||||
|
|
||||||
|
type Column = {
|
||||||
|
field: string;
|
||||||
|
label: string;
|
||||||
|
display: (row: Row) => string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const currFileName = ref<string>("");
|
||||||
|
const currSheet = ref<string>("");
|
||||||
|
const sheets = ref<string[]>([]);
|
||||||
|
const workBook = ref<DataSet>({} as DataSet);
|
||||||
|
const rows = ref<Row[]>([]);
|
||||||
|
const columns = ref<Column[]>([]);
|
||||||
|
|
||||||
|
const exportTypes: string[] = ["xlsx", "xlsb", "csv", "html"];
|
||||||
|
|
||||||
|
let cell = 0;
|
||||||
|
|
||||||
|
function resetCell() {
|
||||||
|
cell = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function display(col: number): (row: Row) => string {
|
||||||
|
return function (row: Row) {
|
||||||
|
return `<span
|
||||||
|
style="user-select: none; display: block"
|
||||||
|
position="${Math.floor(cell++ / columns.value.length)}.${col}"
|
||||||
|
onblur="endEdit(event)"
|
||||||
|
ondblclick="startEdit(event)"
|
||||||
|
onkeydown="endEdit(event)">${row[col] ?? " "}</span>`;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
window.startEdit = function (ev) {
|
||||||
|
ev.target.contentEditable = true;
|
||||||
|
ev.target.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.endEdit = function (ev) {
|
||||||
|
if (ev.key === undefined || ev.key === "Enter") {
|
||||||
|
const pos = ev.target.getAttribute("position").split(".");
|
||||||
|
|
||||||
|
ev.target.contentEditable = false;
|
||||||
|
|
||||||
|
rows.value[pos[0]][pos[1]] = ev.target.innerText;
|
||||||
|
|
||||||
|
workBook.value[currSheet.value] = utils.json_to_sheet(rows.value, {
|
||||||
|
header: columns.value.map((col: Column) => col.field),
|
||||||
|
skipHeader: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function getRowsCols(
|
||||||
|
data: DataSet,
|
||||||
|
sheetName: string
|
||||||
|
): {
|
||||||
|
rows: Row[];
|
||||||
|
cols: Column[];
|
||||||
|
} {
|
||||||
|
const rows: Row[] = utils.sheet_to_json(data[sheetName], { header: 1 });
|
||||||
|
let cols: Column[] = [];
|
||||||
|
|
||||||
|
for (let row of rows) {
|
||||||
|
const keys: string[] = Object.keys(row);
|
||||||
|
|
||||||
|
if (keys.length > cols.length) {
|
||||||
|
cols = keys.map((key) => {
|
||||||
|
return {
|
||||||
|
field: key,
|
||||||
|
label: utils.encode_col(+key),
|
||||||
|
display: display(key),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { rows, cols };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function importFile(ev: ChangeEvent<HTMLInputElement>): Promise<void> {
|
||||||
|
const file = ev.target.files[0];
|
||||||
|
const data = read(await file.arrayBuffer());
|
||||||
|
|
||||||
|
currFileName.value = file.name;
|
||||||
|
currSheet.value = data.SheetNames?.[0];
|
||||||
|
sheets.value = data.SheetNames;
|
||||||
|
workBook.value = data.Sheets;
|
||||||
|
|
||||||
|
selectSheet(currSheet.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportFile(type: string): void {
|
||||||
|
const wb = utils.book_new();
|
||||||
|
|
||||||
|
sheets.value.forEach((sheet) => {
|
||||||
|
utils.book_append_sheet(wb, workBook.value[sheet], sheet);
|
||||||
|
});
|
||||||
|
|
||||||
|
writeFile(wb, `sheet.${type}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectSheet(sheet: string): void {
|
||||||
|
const { rows: newRows, cols: newCols } = getRowsCols(workBook.value, sheet);
|
||||||
|
|
||||||
|
resetCell();
|
||||||
|
|
||||||
|
rows.value = newRows;
|
||||||
|
columns.value = newCols;
|
||||||
|
currSheet.value = sheet;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<header class="imp-exp">
|
||||||
|
<div class="import">
|
||||||
|
<input type="file" id="import" @change="importFile" />
|
||||||
|
<label for="import">import</label>
|
||||||
|
</div>
|
||||||
|
<span>{{ currFileName || "vue-modify demo" }}</span>
|
||||||
|
<div class="export">
|
||||||
|
<span>export</span>
|
||||||
|
<ul>
|
||||||
|
<li v-for="type in exportTypes" @click="exportFile(type)">
|
||||||
|
{{ `.${type}` }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class="sheets">
|
||||||
|
<span
|
||||||
|
v-for="sheet in sheets"
|
||||||
|
@click="selectSheet(sheet)"
|
||||||
|
:class="[currSheet === sheet ? 'selected' : '']"
|
||||||
|
>
|
||||||
|
{{ sheet }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<vue-table-lite
|
||||||
|
:is-static-mode="true"
|
||||||
|
:page-size="50"
|
||||||
|
:columns="columns"
|
||||||
|
:rows="rows"
|
||||||
|
></vue-table-lite>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.imp-exp {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.5rem;
|
||||||
|
font-family: mono;
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import {
|
||||||
|
font-size: medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import input {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import label {
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid;
|
||||||
|
padding: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.export: hover {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.export:hover ul {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.export span {
|
||||||
|
padding: 0.3rem;
|
||||||
|
border: 1px solid;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.export ul {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 5;
|
||||||
|
background-color: white;
|
||||||
|
list-style: none;
|
||||||
|
padding: 0.3rem;
|
||||||
|
border: 1px solid;
|
||||||
|
margin-top: 0.3rem;
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.export ul li {
|
||||||
|
padding: 0.3rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.export ul li:hover {
|
||||||
|
background-color: lightgray;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sheets {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 0.3rem;
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sheets span {
|
||||||
|
border: 1px solid;
|
||||||
|
padding: 0.5rem;
|
||||||
|
margin: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sheets span:hover:not(.selected) {
|
||||||
|
background-color: lightgray;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
background-color: #343a40;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
8
demos/vue-modify/src/env.d.ts
vendored
Normal file
8
demos/vue-modify/src/env.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
declare module '*.vue' {
|
||||||
|
import type { DefineComponent } from 'vue'
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
||||||
|
const component: DefineComponent<{}, {}, any>
|
||||||
|
export default component
|
||||||
|
}
|
4
demos/vue-modify/src/main.ts
Normal file
4
demos/vue-modify/src/main.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { createApp } from 'vue';
|
||||||
|
import App from './App.vue';
|
||||||
|
|
||||||
|
createApp(App).mount('#app');
|
16
demos/vue-modify/tsconfig.json
Normal file
16
demos/vue-modify/tsconfig.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "esnext",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"strict": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"sourceMap": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"lib": ["esnext", "dom"]
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||||
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
|
}
|
8
demos/vue-modify/tsconfig.node.json
Normal file
8
demos/vue-modify/tsconfig.node.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node"
|
||||||
|
},
|
||||||
|
"include": ["vite.config.ts"]
|
||||||
|
}
|
7
demos/vue-modify/vite.config.ts
Normal file
7
demos/vue-modify/vite.config.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [vue()]
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user