Compare commits
4 Commits
sync
...
dba38f71b1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dba38f71b1 | ||
| 0e0b0bf8a2 | |||
| 20458288c2 | |||
| 7bb363d790 |
@@ -50,14 +50,13 @@ wails3 generate bindings -ts
|
||||
Для финальной сборки запустите эту команду в директории проекта:
|
||||
|
||||
```
|
||||
go env -w CGO_ENABLED=1
|
||||
wails3 build -clean -upx -v 2 -webview2 embed
|
||||
PRODUCTION=true wails3 build
|
||||
```
|
||||
|
||||
**Перед релизом не забыть**:
|
||||
|
||||
- поместить все нужные asset'ы в папку assets
|
||||
- изменить версию схемы БД (пока не нужно)
|
||||
- убедиться, что дефолтные данные правильные
|
||||
- убедиться, что приложение запускается
|
||||
- (опционально) поместить все нужные asset'ы в папку assets
|
||||
- приложить сопроводительную записку.
|
||||
|
||||
## Работа без GitHub
|
||||
|
||||
@@ -13,7 +13,7 @@ tasks:
|
||||
cmds:
|
||||
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}
|
||||
vars:
|
||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -ldflags="-w -s"{{else}}-gcflags=all="-l"{{end}}'
|
||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags "production sqlite_icu" -trimpath -ldflags="-w -s"{{else}}-gcflags=all="-l" -tags "sqlite_icu"{{end}}'
|
||||
env:
|
||||
GOOS: darwin
|
||||
CGO_ENABLED: 1
|
||||
|
||||
@@ -13,7 +13,7 @@ tasks:
|
||||
cmds:
|
||||
- go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}
|
||||
vars:
|
||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -ldflags="-w -s"{{else}}-gcflags=all="-l"{{end}}'
|
||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags "production sqlite_icu" -trimpath -ldflags="-w -s"{{else}}-gcflags=all="-l" -tags "sqlite_icu" {{end}}'
|
||||
env:
|
||||
GOOS: linux
|
||||
CGO_ENABLED: 1
|
||||
|
||||
@@ -18,7 +18,7 @@ tasks:
|
||||
- cmd: rm -f *.syso
|
||||
platforms: [linux, darwin]
|
||||
vars:
|
||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -ldflags="-w -s -H windowsgui"{{else}}-gcflags=all="-l"{{end}}'
|
||||
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags "production sqlite_icu" -trimpath -ldflags="-w -s -H windowsgui"{{else}}-gcflags=all="-l" -tags "sqlite_icu"{{end}}'
|
||||
env:
|
||||
GOOS: windows
|
||||
CGO_ENABLED: 1
|
||||
|
||||
@@ -31,7 +31,6 @@ const load = async () => {
|
||||
|
||||
onMounted(async () => {
|
||||
await load();
|
||||
console.log(await SortedByOrder({"Comments": "DESC"}))
|
||||
});
|
||||
|
||||
const scheme: Scheme<Author> = reactive({
|
||||
|
||||
@@ -17,7 +17,6 @@ const pushOrRemove = (option: T) => {
|
||||
} else {
|
||||
selected.value.push(option)
|
||||
}
|
||||
//setNullIds()
|
||||
}
|
||||
|
||||
const setNullIds = () => {
|
||||
@@ -27,12 +26,11 @@ const setNullIds = () => {
|
||||
})
|
||||
}
|
||||
|
||||
//onMounted(setNullIds)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="">
|
||||
<ul class="max-h-48 h-auto overflow-y-auto background rounded-md p-3 w-full border-gray-500 border">
|
||||
<ul class="max-h-48 h-auto overflow-y-auto background rounded-md p-3 w-full native-border">
|
||||
<li v-for="option in options" :key="option.Id" class="flex items-center gap-2">
|
||||
<Checkbox :checked="selected.some(item => item.Id == option.Id)" @click="pushOrRemove(option)" />
|
||||
<label :for="option.Id.toString()">{{ structView(option, path) }}</label>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import Table from "../table/Table.vue";
|
||||
import { onMounted, reactive } from "vue";
|
||||
import {onMounted, reactive, watch} from "vue";
|
||||
import { getDefaultValues } from "../utils/structs/defaults.util";
|
||||
import Service from "./post.service.ts";
|
||||
import type { Scheme } from "../types/scheme.type";
|
||||
@@ -16,6 +16,7 @@ const posttypeService = new PosttypeService();
|
||||
|
||||
import CommentService from "../comment/comment.service.ts";
|
||||
import { SortedByOrder } from "../../bindings/app/internal/services/postservice.ts";
|
||||
import {getDefaultSortOptions} from "../utils/structs/default-sort-options.util.ts";
|
||||
|
||||
const commentService = new CommentService();
|
||||
|
||||
@@ -32,13 +33,12 @@ const load = async () => {
|
||||
(scheme as any).Comments.type!.nested!.values =
|
||||
await commentService.readAll();
|
||||
|
||||
items.value = await service.readAll();
|
||||
items.value = await service.sort(sortOptions.value) ;
|
||||
return items.value;
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await load();
|
||||
console.log(await SortedByOrder({ "Author": "DESC", "Text": "ASC" }));
|
||||
});
|
||||
|
||||
const scheme: Scheme<Post> = reactive({
|
||||
@@ -116,9 +116,6 @@ const scheme: Scheme<Post> = reactive({
|
||||
values: [],
|
||||
field: ["Text"],
|
||||
},
|
||||
},
|
||||
customWindow: {
|
||||
create: true,
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -132,12 +129,16 @@ const validate: Validate<Post> = (entity) => {
|
||||
status: "success",
|
||||
};
|
||||
};
|
||||
|
||||
const search = async (input: string) => {
|
||||
|
||||
}
|
||||
|
||||
const sortOptions = ref(getDefaultSortOptions(scheme))
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Table :scheme :service :get-defaults :load :items :validate >
|
||||
<template #CommentsCreate="{ data }">
|
||||
<p>{{ data }}</p>
|
||||
</template>
|
||||
</Table>
|
||||
<Table :scheme :service :get-defaults :load :items :validate @on-search="search" v-model:sort-options="sortOptions"></Table>
|
||||
</template>
|
||||
|
||||
@@ -4,10 +4,11 @@ import {
|
||||
Delete,
|
||||
GetById,
|
||||
Update,
|
||||
Count,
|
||||
Count, SortedByOrder,
|
||||
} from "../../bindings/app/internal/services/postservice.ts";
|
||||
import type { Post } from "../../bindings/app/internal/services";
|
||||
import type { IService } from "../types/service.type.ts";
|
||||
import type {SortOptions} from "../types/sort-options.type.ts";
|
||||
|
||||
export default class PostService implements IService<Post> {
|
||||
async read(id: number) {
|
||||
@@ -33,4 +34,8 @@ export default class PostService implements IService<Post> {
|
||||
async count() {
|
||||
return await Count();
|
||||
}
|
||||
|
||||
async sort(options: SortOptions<Post>) {
|
||||
return await SortedByOrder(options) as Post[]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,25 @@
|
||||
|
||||
html, body, .background {
|
||||
background: white;
|
||||
color: rgb(51, 65, 85);
|
||||
}
|
||||
|
||||
.secondary-background {
|
||||
background: var(--p-content-background)
|
||||
}
|
||||
|
||||
.native-border {
|
||||
border: 1px solid var(--p-select-border-color);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html, body, .background {
|
||||
background: #121212;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.native-border {
|
||||
border: 1px solid rgb(100, 100, 109);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -62,7 +62,7 @@ async function handleSave() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model:visible="showCreate">
|
||||
<Dialog v-model:visible="showCreate" class="w-[500px]">
|
||||
<template #header>
|
||||
<h1>{{ props.updateMode ? 'Изменить' : 'Создать' }} {{ props.name?.toLowerCase() }}</h1>
|
||||
</template>
|
||||
|
||||
25
frontend/src/table/SortingOptions.vue
Normal file
25
frontend/src/table/SortingOptions.vue
Normal file
@@ -0,0 +1,25 @@
|
||||
<script setup lang="ts" generic="T extends IEntity">
|
||||
import type {IEntity} from "../types/entity.type.ts";
|
||||
import type {SortOptions} from "../types/sort-options.type.ts";
|
||||
import type {Scheme} from "../types/scheme.type.ts";
|
||||
import {Select} from 'primevue'
|
||||
import {watch} from "vue";
|
||||
|
||||
|
||||
const options = defineModel<SortOptions<T>>()
|
||||
const optionsKeys = Object.keys(options.value as T) as (keyof T)[]
|
||||
|
||||
defineProps<{
|
||||
scheme: Scheme<T>
|
||||
load: () => Promise<T[]>
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ul class="flex flex-col gap-2 native-border secondary-background p-3 rounded-md">
|
||||
<li v-for="optionKey in optionsKeys" class="flex items-center justify-between w-full">
|
||||
<h1>{{ scheme[optionKey].russian }}</h1>
|
||||
<Select size="small" class="w-24" :options="['ASC', 'DESC']" v-model="options![optionKey]" @value-change="load"></Select>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
@@ -1,20 +1,18 @@
|
||||
<script setup lang="ts" generic="T extends IEntity">
|
||||
import {onMounted, ref, watch, type UnwrapRef} from "vue";
|
||||
import type {TableProps} from "../types/table-props.type";
|
||||
import { DataTable, Column, Button } from "primevue";
|
||||
import {DataTable, Column, Button, InputText} from "primevue";
|
||||
import {manyStructsView} from "../utils/structs/structs-view.util";
|
||||
import type {TableEmits} from "../types/table-emits.type";
|
||||
import FloatingButton from "../components/buttons/FloatingButton.vue";
|
||||
import type {IEntity} from "../types/entity.type";
|
||||
import DialogWindow from "./DialogWindow.vue";
|
||||
import {viewDate} from "../utils/date/view.util";
|
||||
import SortingOptions from "./SortingOptions.vue";
|
||||
import type {SortOptions} from "../types/sort-options.type.ts";
|
||||
|
||||
const props = defineProps<TableProps<T>>();
|
||||
|
||||
onMounted(async () => {
|
||||
props.load()
|
||||
});
|
||||
|
||||
type Key = keyof T;
|
||||
const keys = Object.keys(props.scheme) as Key[];
|
||||
const emits = defineEmits<TableEmits>();
|
||||
@@ -76,27 +74,49 @@ watch(() => props.items, () => {
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const input = ref('')
|
||||
const sortOptions = defineModel<SortOptions<T>>('sort-options');
|
||||
const showSortOptions = ref(false)
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="m-2 flex flex-col items-center gap-2">
|
||||
<div class="flex flex-col gap-2 relative">
|
||||
<div class="flex items-center justify-center gap-2 h-10">
|
||||
<Button severity="secondary" class="h-full aspect-square" @click="showSortOptions = !showSortOptions">
|
||||
<span class="pi pi-sort"></span>
|
||||
</Button>
|
||||
|
||||
<InputText class="h-full w-64" v-model="input"/>
|
||||
<Button severity="secondary" class="h-full aspect-square" @click="emits('onSearch', input)">
|
||||
<span class="pi pi-search"></span>
|
||||
</Button>
|
||||
</div>
|
||||
<SortingOptions v-model="sortOptions as SortOptions<T>" :scheme v-if="showSortOptions"
|
||||
class="absolute z-10 w-full top-full translate-y-2" :load="props.load"></SortingOptions>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<DialogWindow :name :load :items :validate :scheme :service :get-defaults v-model:item="<T>createItem"
|
||||
v-model:show="showCreate" @on-save="data => emits('onSave', data)"
|
||||
@on-save-create="data => emits('onSaveCreate', data)">
|
||||
<template v-for="key in keys" #[key]="{ data }">
|
||||
<slot :name="<string>key" :data></slot>
|
||||
<slot :name="<string>key" :data="data"></slot>
|
||||
</template>
|
||||
<template v-for="key in keys" #[createSlotName(key)]="{ data }">
|
||||
<slot :name="createSlotName(key)" :data></slot>
|
||||
<slot :name="createSlotName(key)" :data="data"></slot>
|
||||
</template>
|
||||
</DialogWindow>
|
||||
<DialogWindow :name :load :items :validate :scheme update-mode :service :get-defaults v-model:item="<T>updateItem"
|
||||
v-model:show="showUpdate" @on-save="data => emits('onSave', data)"
|
||||
@on-save-update="data => emits('onSaveUpdate', data)">
|
||||
<template v-for="key in keys" #[key]="{ data }">
|
||||
<slot :name="<string>key" :data></slot>
|
||||
<slot :name="<string>key" :data="data"></slot>
|
||||
</template>
|
||||
<template v-for="key in keys" #[updateSlotName(key)]="{ data }">
|
||||
<slot :name="updateSlotName(key)" :data></slot>
|
||||
<slot :name="updateSlotName(key)" :data="data"></slot>
|
||||
</template>
|
||||
</DialogWindow>
|
||||
<div>
|
||||
@@ -137,6 +157,14 @@ watch(() => props.items, () => {
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
<template #paginatorstart>
|
||||
<Button severity="secondary" @click="props.load">
|
||||
<span class="pi pi-refresh"></span>
|
||||
</Button>
|
||||
</template>
|
||||
<template #paginatorend>
|
||||
<span></span>
|
||||
</template>
|
||||
</DataTable>
|
||||
<FloatingButton @click="handleFloatingButtonClick"/>
|
||||
</div>
|
||||
|
||||
6
frontend/src/types/sort-options.type.ts
Normal file
6
frontend/src/types/sort-options.type.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import type { IEntity } from "./entity.type";
|
||||
import type { Sorting } from "./sorting.type";
|
||||
|
||||
export type SortOptions<T extends IEntity> = {
|
||||
[key in keyof Partial<T>]: Sorting
|
||||
}
|
||||
1
frontend/src/types/sorting.type.ts
Normal file
1
frontend/src/types/sorting.type.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type Sorting = "DESC" | "ASC"
|
||||
@@ -9,4 +9,5 @@ export type TableEmits = {
|
||||
(e: 'onSaveUpdate', data: any): Promise<void> | void
|
||||
(e: 'onSaveCreate', data: any): Promise<void> | void
|
||||
(e: 'onSave', data: any): Promise<void> | void
|
||||
(e: 'onSearch', input: string): Promise<void> | void
|
||||
}
|
||||
16
frontend/src/utils/structs/default-sort-options.util.ts
Normal file
16
frontend/src/utils/structs/default-sort-options.util.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import type { IEntity } from "../../types/entity.type";
|
||||
import type { Scheme } from "../../types/scheme.type";
|
||||
import type { SortOptions } from "../../types/sort-options.type";
|
||||
|
||||
export const getDefaultSortOptions = <T extends IEntity>(scheme: Scheme<T>): SortOptions<T> => {
|
||||
const keys = Object.keys(scheme) as (keyof T)[]
|
||||
const result: Partial<SortOptions<T>> = {}
|
||||
|
||||
keys.forEach(key => {
|
||||
if (!scheme[key].hidden && key !== 'entityId' && !scheme[key].many) {
|
||||
result[key] = 'ASC'
|
||||
}
|
||||
})
|
||||
|
||||
return result as SortOptions<T>
|
||||
}
|
||||
18
package-lock.json
generated
18
package-lock.json
generated
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"name": "boilerplate",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@wailsio/runtime": "3.0.0-alpha.66"
|
||||
}
|
||||
},
|
||||
"node_modules/@wailsio/runtime": {
|
||||
"version": "3.0.0-alpha.66",
|
||||
"resolved": "https://registry.npmjs.org/@wailsio/runtime/-/runtime-3.0.0-alpha.66.tgz",
|
||||
"integrity": "sha512-ENLu8rn1griL1gFHJqkq1i+BVxrrA0JPJHYneUJYuf/s54kjuQViW0RKDEe/WTDo56ABpfykrd/T8OYpPUyXUw==",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@wailsio/runtime": "3.0.0-alpha.66"
|
||||
}
|
||||
}
|
||||
22
pnpm-lock.yaml
generated
22
pnpm-lock.yaml
generated
@@ -1,22 +0,0 @@
|
||||
lockfileVersion: '9.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@wailsio/runtime':
|
||||
specifier: 3.0.0-alpha.66
|
||||
version: 3.0.0-alpha.66
|
||||
|
||||
packages:
|
||||
|
||||
'@wailsio/runtime@3.0.0-alpha.66':
|
||||
resolution: {integrity: sha512-ENLu8rn1griL1gFHJqkq1i+BVxrrA0JPJHYneUJYuf/s54kjuQViW0RKDEe/WTDo56ABpfykrd/T8OYpPUyXUw==}
|
||||
|
||||
snapshots:
|
||||
|
||||
'@wailsio/runtime@3.0.0-alpha.66': {}
|
||||
Reference in New Issue
Block a user