feat: excel custom data type export
This commit is contained in:
@@ -1,39 +1,42 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from "vue";
|
||||||
import {Events} from "@wailsio/runtime";
|
import { Events } from "@wailsio/runtime";
|
||||||
import * as PostService from "../../bindings/app/internal/services/postservice";
|
import * as PostService from "../../bindings/app/internal/services/postservice";
|
||||||
|
|
||||||
const name = ref('')
|
const name = ref("");
|
||||||
const result = ref('Please enter your name below 👇')
|
const result = ref("Please enter your name below 👇");
|
||||||
const time = ref('Listening for Time event...')
|
const time = ref("Listening for Time event...");
|
||||||
|
|
||||||
const doGreet = () => {
|
const doGreet = () => {
|
||||||
let localName = name.value;
|
let localName = name.value;
|
||||||
if (!localName) {
|
if (!localName) {
|
||||||
localName = 'anonymous';
|
localName = "anonymous";
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
console.log(await PostService.GetById(5))
|
console.log(await PostService.GetById(5));
|
||||||
await PostService.ExportToExcel()
|
});
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<h1>Kuzbass</h1>
|
<h1>Kuzbass</h1>
|
||||||
|
|
||||||
<div class="result"></div>
|
<div class="result"></div>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="input-box">
|
<div class="input-box">
|
||||||
<input class="input" v-model="name" type="text" autocomplete="off"/>
|
<input
|
||||||
<button class="btn" @click="doGreet">Greet</button>
|
class="input"
|
||||||
|
v-model="name"
|
||||||
|
type="text"
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
<button class="btn" @click="doGreet">Greet</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<div><p>Click on the Wails logo to learn more</p></div>
|
<div><p>Click on the Wails logo to learn more</p></div>
|
||||||
<div><p></p></div>
|
<div><p></p></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
"reflect"
|
"reflect"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TableHeaders struct {
|
type TableHeaders struct {
|
||||||
@@ -56,22 +58,34 @@ func ExportEntityToSpreadsheet[T any](filename, sheetName string, entity T, prov
|
|||||||
// TODO: appearance
|
// TODO: appearance
|
||||||
for i, item := range items {
|
for i, item := range items {
|
||||||
structValue := reflect.ValueOf(item).Elem()
|
structValue := reflect.ValueOf(item).Elem()
|
||||||
for j := range structValue.NumField() {
|
|
||||||
|
for j := 0; j < structValue.NumField(); j++ {
|
||||||
if slices.Contains(headers.IgnoredFieldsIndices, j) {
|
if slices.Contains(headers.IgnoredFieldsIndices, j) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
field := structValue.Field(j)
|
field := structValue.Field(j)
|
||||||
|
|
||||||
if isPrimitive(field.Type()) {
|
if isPrimitive(field.Type()) {
|
||||||
fieldValue := reflect.ValueOf(field)
|
fieldValue := field.Interface()
|
||||||
|
|
||||||
cellName, err := GetCellNameByIndices(j, i+1)
|
cellName, err := GetCellNameByIndices(j, i+1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("Field %s value: %v\n", cellName, fieldValue.Interface())
|
|
||||||
|
|
||||||
err = file.SetCellValue(sheetName, cellName, fieldValue.Interface())
|
cellType := structValue.Type().Field(j).Tag.Get(CellTypeTag)
|
||||||
|
|
||||||
|
var cellValue any
|
||||||
|
|
||||||
|
switch cellType {
|
||||||
|
case TimestampTag:
|
||||||
|
cellValue = time.Unix(field.Int(), 0)
|
||||||
|
case DurationTag:
|
||||||
|
cellValue = time.Duration(field.Int())
|
||||||
|
default:
|
||||||
|
cellValue = fieldValue
|
||||||
|
}
|
||||||
|
|
||||||
|
slog.Debug("Field %s value: %v, %s\n", cellName, cellValue, cellType)
|
||||||
|
err = file.SetCellValue(sheetName, cellName, cellValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -79,12 +93,7 @@ func ExportEntityToSpreadsheet[T any](filename, sheetName string, entity T, prov
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filepath, err := dialogs.SaveFileDialog("Экспорт данных", filename)
|
if err := WriteData(file, filename); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := file.SaveAs(filepath); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,6 +223,18 @@ func ApplyStyleHeaders(file *excelize.File, sheetName string, headers TableHeade
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func WriteData(file *excelize.File) {
|
func WriteData(file *excelize.File, filename string) error {
|
||||||
|
filepath, err := dialogs.SaveFileDialog("Экспорт данных", filename)
|
||||||
|
|
||||||
|
if !strings.HasSuffix(filepath, ".xlsx") {
|
||||||
|
filepath += ".xlsx"
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := file.SaveAs(filepath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
10
internal/extras/excel/tags.go
Normal file
10
internal/extras/excel/tags.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package excel
|
||||||
|
|
||||||
|
const (
|
||||||
|
CellTypeTag = "cellType"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TimestampTag = "timestamp"
|
||||||
|
DurationTag = "duration"
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user