vue-modify demo [ci skip]

This commit is contained in:
0xc0Der 2022-03-15 15:11:02 +00:00
parent 9a3294c955
commit 2cbc28d6ed
9 changed files with 339 additions and 0 deletions

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?

@ -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
```

@ -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"
}
}

@ -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] ?? "&nbsp;"}</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

@ -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
}

@ -0,0 +1,4 @@
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#app');

@ -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" }]
}

@ -0,0 +1,8 @@
{
"compilerOptions": {
"composite": true,
"module": "esnext",
"moduleResolution": "node"
},
"include": ["vite.config.ts"]
}

@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()]
})