This commit is contained in:
xds
2025-10-27 15:12:00 +03:00
commit a198c703ef
47 changed files with 2141 additions and 0 deletions

46
src/stores/spaceStore.ts Normal file
View File

@@ -0,0 +1,46 @@
import {defineStore} from "pinia";
import {ref, watch} from "vue";
import {spaceService} from "@/services/space-service";
import {Space} from "@/models/space";
export const useSpaceStore = defineStore('space', () => {
const spaces = ref<Space[]>([]);
const getSpaces = async () => {
await spaceService.fetchSpaces().then((res) => {
spaces.value = res;
const spaceId = localStorage.getItem("spaceId");
const selectedSpace = spaces.value.find((s: Space) => s.id.toString() === spaceId) || null;
selectedSpaceId.value = selectedSpace?.id;
selectedSpaceName.value = selectedSpace?.name;
})
return spaces.value;
}
const selectedSpaceId = ref<number | undefined>(undefined);
const selectedSpaceName = ref<string | undefined>(undefined);
const getSpace = async () => {
const spaceId = selectedSpaceId.value;
if (!spaceId) {
return null;
}
return spaceService.fetchSpace(spaceId);
};
const setSpace = (newSpaceId: number, newSpaceName: string) => {
if (selectedSpaceId.value != newSpaceId) {
selectedSpaceId.value = newSpaceId;
selectedSpaceName.value = newSpaceName;
localStorage.setItem("spaceId", newSpaceId.toString());
}
}
return {spaces, getSpaces, getSpace, selectedSpaceId, selectedSpaceName, setSpace};
})

View File

@@ -0,0 +1,70 @@
import { defineStore } from "pinia";
import { computed, reactive, ref } from "vue";
import { useSpaceStore } from "@/stores/spaceStore";
export interface ToolbarButton {
id?: string;
text?: string;
icon?: string;
to?: string;
onClickId?: string;
disabled?: boolean;
class?: string;
title?: string;
}
export type ToolbarConfig =
| ToolbarButton[]
| ((ctx: { spaceStore: ReturnType<typeof useSpaceStore> }) => ToolbarButton[]);
export const useToolbarStore = defineStore("toolbar", () => {
const spaceStore = useSpaceStore();
// обработчики
const handlers: Record<string, () => void> = reactive({});
const registerHandler = (key: string, fn: () => void) => (handlers[key] = fn);
const unregisterHandler = (key: string) => delete handlers[key];
const invoke = (key?: string) => {
if (!key) return;
const fn = handlers[key];
if (typeof fn === "function") fn();
};
// текущие кнопки (сделал ref — теперь реактивно)
const _current = ref<ToolbarButton[]>([]);
const set = (items: ToolbarButton[]) => void (_current.value = items);
const clear = () => void (_current.value = []);
const setByConfig = (config?: ToolbarConfig) => {
if (!config) return clear();
_current.value =
typeof config === "function" ? config({ spaceStore }) : config;
};
const defaults = computed<ToolbarButton[]>(() => [
{
id: 'space',
text: spaceStore.selectedSpaceName ?? 'Select Space',
icon: '',
onClickId: 'openSpacePicker',
},
]);
const current = computed<ToolbarButton[]>(() => {
const map = new Map<string, ToolbarButton>();
for (const b of defaults.value) map.set(b.id ?? crypto.randomUUID(), b);
for (const b of _current.value) map.set(b.id ?? crypto.randomUUID(), b);
return Array.from(map.values());
});
return {
current,
registerHandler,
unregisterHandler,
invoke,
set,
clear,
setByConfig,
};
});

81
src/stores/userStore.ts Normal file
View File

@@ -0,0 +1,81 @@
import {defineStore} from 'pinia';
import {ref} from 'vue';
import apiClient from "@/network/axiosSetup";
import {useRoute, useRouter} from "vue-router";
import {useToast} from "primevue/usetoast";
import {User} from "@/models/user";
export const useUserStore = defineStore('user', () => {
const toast = useToast();
const user = ref<User | null>(null);
const loadingUser = ref(true);
const router = useRouter();
const route = useRoute();
async function fetchUserProfile() {
// Убираем проверку на `loadingUser`, чтобы не блокировать запрос
if (!user.value) {
loadingUser.value = true;
try {
await apiClient.get('/auth/me')
.then((res: any) => user.value = res.data)
.catch((err: Error) => {
console.log(err)
throw err
})
} catch (error) {
console.error('Ошибка при загрузке данных пользователя:', error);
user.value = null;
} finally {
loadingUser.value = false; // Сбрасываем флаг `loadingUser` в `false` после завершения
}
}
}
// Основная функция для логина
async function login(username: string, password: string) {
try {
let response;
response = await apiClient.post('/auth/login', {
username: username,
password: password,
});
const token = response.data.token;
console.log(token);
localStorage.setItem('token', token);
apiClient.defaults.headers.common['Authorization'] = `Bearer ${token}`;
toast.add({severity: 'success', summary: 'Вход выполнен', detail: 'Добро пожаловать!', life: 3000})
await fetchUserProfile();
await router.push(route.query['back'] ? route.query['back'].toString() : '/');
} catch (error: any) {
console.error(error);
toast.add({
severity: 'error',
summary: 'Ошибка авторизации',
detail: error.response.data.message,
life: 3000
})
}
}
async function register(username: string, password: string, firstName: string) {
try {
let response = await apiClient.post('/auth/register', {
username: username,
password: password,
firstName: firstName
})
return response.data
} catch (error) {
// console.error(error);
throw error
}
}
return {user, loadingUser, fetchUserProfile, login, register};
});