From bc63d8662924619ab08534b13a0ef9d3d2e0c2e2 Mon Sep 17 00:00:00 2001 From: Dmatrushka19 Date: Thu, 23 Apr 2026 21:55:16 +0300 Subject: [PATCH 01/15] =?UTF-8?q?=D1=84=D0=B0=D0=B9=D0=BB,=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=B4=D0=B0=D1=8E=D1=89=D0=B8=D0=B9=20ZachetCard.vue=20=D0=BD?= =?UTF-8?q?=D0=B0=D1=80=D1=83=D0=B6=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/ZachetCard/index.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/modules/ZachetCard/index.ts diff --git a/src/modules/ZachetCard/index.ts b/src/modules/ZachetCard/index.ts new file mode 100644 index 0000000..8a947c7 --- /dev/null +++ b/src/modules/ZachetCard/index.ts @@ -0,0 +1 @@ +export { default as ZachetCard } from './ZachetCard.vue'; From 29ea5299909fe339ad44e99fb941c5d7608f357f Mon Sep 17 00:00:00 2001 From: Dmatrushka19 Date: Thu, 23 Apr 2026 21:55:48 +0300 Subject: [PATCH 02/15] =?UTF-8?q?=D0=BF=D1=80=D0=B5=D0=BE=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=B7=D1=83=D0=B5=D1=82=20=D0=BE=D1=82=D0=B2=D0=B5=D1=82?= =?UTF-8?q?=20API=20=D0=B2=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D0=B5,=20?= =?UTF-8?q?=D1=83=D0=B4=D0=BE=D0=B1=D0=BD=D1=8B=D0=B5=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/ZachetCard/controller/mapper.ts | 66 +++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 src/modules/ZachetCard/controller/mapper.ts diff --git a/src/modules/ZachetCard/controller/mapper.ts b/src/modules/ZachetCard/controller/mapper.ts new file mode 100644 index 0000000..845539c --- /dev/null +++ b/src/modules/ZachetCard/controller/mapper.ts @@ -0,0 +1,66 @@ +import type { UserdataItem, ZachetCardData } from './types'; + +const FALLBACK = '—'; + +function normalizeValue(value?: string | null): string | null { + if (typeof value !== 'string') return null; + + const trimmed = value.trim(); + + return trimmed.length ? trimmed : null; +} + +function getValue(items: UserdataItem[], category: string, param: string): string | null { + const item = items.find(entry => entry.category === category && entry.param === param); + + return normalizeValue(item?.value); +} + +function resolveUnionCardNumber(items: UserdataItem[]): string { + return ( + getValue(items, 'Учёба', 'Номер профсоюзного билета') ?? + getValue(items, 'Учетные данные', 'Номер профсоюзного билета') ?? + FALLBACK + ); +} + +function resolvePhotoUrl(items: UserdataItem[]): string | undefined { + const value = getValue(items, 'Личная информация', 'Фото'); + + if (!value) return undefined; + + return value; +} + +export function mapUserdataToZachetCard(items: UserdataItem[]): ZachetCardData { + logZachetCardMapper('start mapping items', { items }); + + const mappedCard: ZachetCardData = { + unionCardNumber: resolveUnionCardNumber(items), + fullNameRu: getValue(items, 'Личная информация', 'Полное имя') ?? FALLBACK, + fullNameEn: FALLBACK, + birthDate: getValue(items, 'Личная информация', 'Дата рождения') ?? FALLBACK, + facultyRu: getValue(items, 'Учёба', 'Факультет') ?? FALLBACK, + facultyEn: FALLBACK, + statusRu: getValue(items, 'Учёба', 'Ступень обучения') ?? FALLBACK, + statusEn: FALLBACK, + photoUrl: resolvePhotoUrl(items), + }; + + logZachetCardMapper('mapped card result', mappedCard); + + return mappedCard; +} + +function logZachetCardMapper(message: string, payload?: unknown) { + if (!import.meta.env.DEV) { + return; + } + + if (payload === undefined) { + console.log('[ZachetCard][mapper]', message); + return; + } + + console.log('[ZachetCard][mapper]', message, payload); +} From d66f584eaa01d9488e754f37962acffbce1fb4cd Mon Sep 17 00:00:00 2001 From: Dmatrushka19 Date: Thu, 23 Apr 2026 21:56:37 +0300 Subject: [PATCH 03/15] =?UTF-8?q?Vue-=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8F,=20?= =?UTF-8?q?=D0=BA=D0=BE=D1=82=D0=BE=D1=80=D1=8B=D0=B9=20=D1=80=D0=B8=D1=81?= =?UTF-8?q?=D1=83=D0=B5=D1=82=20=D0=BA=D0=B0=D1=80=D1=82=D1=83=20=D0=97?= =?UTF-8?q?=D0=B0=D1=87=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/ZachetCard/ZachetCard.vue | 278 ++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 src/modules/ZachetCard/ZachetCard.vue diff --git a/src/modules/ZachetCard/ZachetCard.vue b/src/modules/ZachetCard/ZachetCard.vue new file mode 100644 index 0000000..3751e60 --- /dev/null +++ b/src/modules/ZachetCard/ZachetCard.vue @@ -0,0 +1,278 @@ + + + + + From 1cb028782b32ba5731b7c388c50f713fc70a4900 Mon Sep 17 00:00:00 2001 From: Dmatrushka19 Date: Thu, 23 Apr 2026 21:58:10 +0300 Subject: [PATCH 04/15] =?UTF-8?q?=D0=B4=D0=B5=D1=80=D0=B3=D0=B0=D0=B5?= =?UTF-8?q?=D1=82=20=D1=80=D1=83=D1=87=D0=BA=D1=83=20=D0=B8=20=D1=85=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=82=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/ZachetCard/controller/store.ts | 91 ++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/modules/ZachetCard/controller/store.ts diff --git a/src/modules/ZachetCard/controller/store.ts b/src/modules/ZachetCard/controller/store.ts new file mode 100644 index 0000000..2718489 --- /dev/null +++ b/src/modules/ZachetCard/controller/store.ts @@ -0,0 +1,91 @@ +import { defineStore } from 'pinia'; +import { ref } from 'vue'; +import { UserdataApi } from '@/api/controllers/UserdataApi'; +import { mapUserdataToZachetCard } from './mapper'; +import type { ZachetCardData, UserdataResponse } from './types'; + +export const useZachetCardStore = defineStore('zachetCard', () => { + const cards = ref>({}); + const loadingByUserId = ref>({}); + const errorByUserId = ref>({}); + + async function fetchCard(userId: number, force = false): Promise { + logZachetCardStore('fetchCard called', { userId, force }); + + if (!force && cards.value[userId]) { + logZachetCardStore('return cached card', { + userId, + card: cards.value[userId], + }); + + return cards.value[userId]; + } + + loadingByUserId.value[userId] = true; + errorByUserId.value[userId] = null; + + try { + const response = await UserdataApi.getUser(userId); + const data = response?.data as UserdataResponse | undefined; + + logZachetCardStore('raw response data', data); + + const items = Array.isArray(data?.items) ? data.items : []; + const mappedCard = mapUserdataToZachetCard(items); + + cards.value[userId] = mappedCard; + + logZachetCardStore('card saved to store', { + userId, + card: mappedCard, + }); + + return mappedCard; + } catch (error) { + errorByUserId.value[userId] = 'Не удалось загрузить данные карты'; + errorZachetCardStore('fetchCard error', error); + + return null; + } finally { + loadingByUserId.value[userId] = false; + logZachetCardStore('fetchCard finished', { + userId, + loading: loadingByUserId.value[userId], + error: errorByUserId.value[userId], + }); + } + } + + return { + cards, + loadingByUserId, + errorByUserId, + fetchCard, + }; +}); + +function logZachetCardStore(message: string, payload?: unknown) { + if (!import.meta.env.DEV) { + return; + } + + if (payload === undefined) { + console.log('[ZachetCard][store]', message); + return; + } + + console.log('[ZachetCard][store]', message, payload); +} + +function errorZachetCardStore(message: string, payload?: unknown) { + if (!import.meta.env.DEV) { + return; + } + + if (payload === undefined) { + console.error('[ZachetCard][store]', message); + return; + } + + console.error('[ZachetCard][store]', message, payload); +} From ec5ea90d547705990ce93a1c847af1e3d124b7c4 Mon Sep 17 00:00:00 2001 From: Dmatrushka19 Date: Thu, 23 Apr 2026 22:00:17 +0300 Subject: [PATCH 05/15] =?UTF-8?q?=D1=81=D0=BB=D0=BE=D0=B2=D0=B0=D1=80?= =?UTF-8?q?=D1=8C=20=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=BE=D0=B2=20?= =?UTF-8?q?=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/ZachetCard/controller/types.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/modules/ZachetCard/controller/types.ts diff --git a/src/modules/ZachetCard/controller/types.ts b/src/modules/ZachetCard/controller/types.ts new file mode 100644 index 0000000..810a31e --- /dev/null +++ b/src/modules/ZachetCard/controller/types.ts @@ -0,0 +1,21 @@ +export interface UserdataItem { + category: string; + param: string; + value?: string | null; +} + +export interface UserdataResponse { + items: UserdataItem[]; +} + +export interface ZachetCardData { + unionCardNumber: string; + fullNameRu: string; + fullNameEn: string; + birthDate: string; + facultyRu: string; + facultyEn: string; + statusRu: string; + statusEn: string; + photoUrl?: string; +} From 76e54e87b57f99bac8637d8f87bfaae6ea904ca5 Mon Sep 17 00:00:00 2001 From: Dmatrushka19 Date: Thu, 23 Apr 2026 22:01:38 +0300 Subject: [PATCH 06/15] =?UTF-8?q?=D1=83=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7?= =?UTF-8?q?=D0=BA=D0=BE=D0=B9=20=D0=BA=D0=B0=D1=80=D1=82=D0=BE=D1=87=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=B8=20=D0=B2=D1=8B=D0=B4=D0=B0=D1=87=D0=B0=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D1=83=20=D1=83?= =?UTF-8?q?=D0=B6=D0=B5=20=D0=B3=D0=BE=D1=82=D0=BE=D0=B2=D0=BE=D0=B3=D0=BE?= =?UTF-8?q?=20=D1=81=D0=BE=D1=81=D1=82=D0=BE=D1=8F=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BE=D1=82=D0=BE=D0=B1=D1=80=D0=B0=D0=B6?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/useZachetCardController.ts | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/modules/ZachetCard/controller/useZachetCardController.ts diff --git a/src/modules/ZachetCard/controller/useZachetCardController.ts b/src/modules/ZachetCard/controller/useZachetCardController.ts new file mode 100644 index 0000000..c14cb0f --- /dev/null +++ b/src/modules/ZachetCard/controller/useZachetCardController.ts @@ -0,0 +1,102 @@ +import { computed, onMounted, watch } from 'vue'; +import { useProfileStore } from '@/store/profile'; +import { useZachetCardStore } from './store'; + +interface UseZachetCardControllerProps { + userId?: number; +} + +export function useZachetCardController(props: UseZachetCardControllerProps) { + const profileStore = useProfileStore(); + const zachetCardStore = useZachetCardStore(); + + const resolvedUserId = computed(() => props.userId ?? profileStore.id ?? null); + + const card = computed(() => { + const userId = resolvedUserId.value; + + if (!userId) return null; + + return zachetCardStore.cards[userId] ?? null; + }); + + const loading = computed(() => { + const userId = resolvedUserId.value; + + if (!userId) return false; + + return Boolean(zachetCardStore.loadingByUserId[userId]); + }); + + const error = computed(() => { + const userId = resolvedUserId.value; + + if (!userId) return 'Не найден id пользователя'; + + return zachetCardStore.errorByUserId[userId] ?? null; + }); + + async function load(force = false) { + const userId = resolvedUserId.value; + + logZachetCardController('load called', { + userId, + force, + }); + + if (!userId) { + logZachetCardController('load skipped because userId is empty'); + return; + } + + await zachetCardStore.fetchCard(userId, force); + } + + async function reload() { + logZachetCardController('reload called'); + await load(true); + } + + onMounted(() => { + logZachetCardController('controller mounted', { + resolvedUserId: resolvedUserId.value, + }); + + void load(); + }); + + watch( + resolvedUserId, + (nextUserId, prevUserId) => { + logZachetCardController('resolvedUserId changed', { + prevUserId, + nextUserId, + }); + + if (nextUserId && nextUserId !== prevUserId) { + void load(); + } + }, + { immediate: false } + ); + + return { + card, + loading, + error, + reload, + }; +} + +function logZachetCardController(message: string, payload?: unknown) { + if (!import.meta.env.DEV) { + return; + } + + if (payload === undefined) { + console.log('[ZachetCard][controller]', message); + return; + } + + console.log('[ZachetCard][controller]', message, payload); +} From ac7476bcb0971860002a9efc741da1276cc77713 Mon Sep 17 00:00:00 2001 From: Dmatrushka19 Date: Thu, 23 Apr 2026 22:02:23 +0300 Subject: [PATCH 07/15] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BC=D0=B0=D1=80=D1=88=D1=80=D1=83=D1=82=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=B4=D0=B5=D0=B1=D0=B0=D0=B3=D0=B0=20?= =?UTF-8?q?=D0=B8=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D0=B0=20?= =?UTF-8?q?=D0=BE=D1=82=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BA=D0=B0=D1=80=D1=82=D0=BE=D1=87=D0=BA=D0=B8=20?= =?UTF-8?q?=D1=82=D0=B0=D0=BA=D0=B6=D0=B5=20=D0=B4=D0=BB=D1=8F=20=D0=B4?= =?UTF-8?q?=D0=B5=D0=B1=D0=B0=D0=B3=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/router/index.ts | 11 ++++ src/views/debug/ZachetCardDebugView.vue | 77 +++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 src/views/debug/ZachetCardDebugView.vue diff --git a/src/router/index.ts b/src/router/index.ts index fbf1afc..d06c660 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -69,6 +69,17 @@ const routes: RouteRecordRaw[] = [ path: '/:pathMatch(.*)', component: () => import('@/views/error/Error404View.vue'), }, + { + path: '/debug/zachet-card', + component: () => import('@/views/debug/ZachetCardDebugView.vue'), + beforeEnter: () => { + const token = LocalStorage.get(LocalStorageItem.Token); + + if (!token) { + return { path: '/auth' }; + } + }, + }, ]; const router = createRouter({ diff --git a/src/views/debug/ZachetCardDebugView.vue b/src/views/debug/ZachetCardDebugView.vue new file mode 100644 index 0000000..0e2be5a --- /dev/null +++ b/src/views/debug/ZachetCardDebugView.vue @@ -0,0 +1,77 @@ + + + + + From 8de3c8b3ec758a274c76911bc1791645a9272c29 Mon Sep 17 00:00:00 2001 From: Dmatrushka19 Date: Fri, 24 Apr 2026 23:14:34 +0300 Subject: [PATCH 08/15] =?UTF-8?q?=D0=BF=D0=BE=D1=87=D0=B8=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BF=D1=80=D0=BE=D0=BA=D0=B8=D0=B4=D1=8B=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20id=20=D0=B2=D0=BD=D1=83=D1=82=D1=80=D1=8C?= =?UTF-8?q?=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8F.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/useZachetCardController.ts | 87 +++++++++++++++---- 1 file changed, 71 insertions(+), 16 deletions(-) diff --git a/src/modules/ZachetCard/controller/useZachetCardController.ts b/src/modules/ZachetCard/controller/useZachetCardController.ts index c14cb0f..6cdba01 100644 --- a/src/modules/ZachetCard/controller/useZachetCardController.ts +++ b/src/modules/ZachetCard/controller/useZachetCardController.ts @@ -1,5 +1,6 @@ -import { computed, onMounted, watch } from 'vue'; +import { computed, onMounted, ref, watch } from 'vue'; import { useProfileStore } from '@/store/profile'; +import { AuthApi } from '@/api'; import { useZachetCardStore } from './store'; interface UseZachetCardControllerProps { @@ -10,7 +11,7 @@ export function useZachetCardController(props: UseZachetCardControllerProps) { const profileStore = useProfileStore(); const zachetCardStore = useZachetCardStore(); - const resolvedUserId = computed(() => props.userId ?? profileStore.id ?? null); + const resolvedUserId = ref(props.userId ?? profileStore.id ?? null); const card = computed(() => { const userId = resolvedUserId.value; @@ -36,16 +37,59 @@ export function useZachetCardController(props: UseZachetCardControllerProps) { return zachetCardStore.errorByUserId[userId] ?? null; }); - async function load(force = false) { - const userId = resolvedUserId.value; + async function ensureUserId(): Promise { + if (props.userId) { + logZachetCardController('using userId from props', { userId: props.userId }); + resolvedUserId.value = props.userId; + return props.userId; + } + + if (profileStore.id) { + logZachetCardController('using userId from profileStore', { userId: profileStore.id }); + resolvedUserId.value = profileStore.id; + return profileStore.id; + } + + try { + logZachetCardController('profileStore.id is empty, requesting AuthApi.getMe'); + + const { data: me } = await AuthApi.getMe([ + 'auth_methods', + 'groups', + 'indirect_groups', + 'session_scopes', + 'user_scopes', + ]); + + if (!me?.id) { + logZachetCardController('AuthApi.getMe returned empty id', { me }); + return null; + } + + profileStore.id = me.id; + resolvedUserId.value = me.id; + + logZachetCardController('userId resolved from AuthApi.getMe', { userId: me.id }); + + return me.id; + } catch (error) { + errorZachetCardController('failed to resolve userId via AuthApi.getMe', error); + return null; + } + } + async function load(force = false) { logZachetCardController('load called', { - userId, + userIdFromProps: props.userId, + userIdFromStore: profileStore.id, + resolvedUserId: resolvedUserId.value, force, }); + const userId = await ensureUserId(); + if (!userId) { - logZachetCardController('load skipped because userId is empty'); + logZachetCardController('load skipped because userId is empty after ensureUserId'); return; } @@ -59,6 +103,8 @@ export function useZachetCardController(props: UseZachetCardControllerProps) { onMounted(() => { logZachetCardController('controller mounted', { + userIdFromProps: props.userId, + userIdFromStore: profileStore.id, resolvedUserId: resolvedUserId.value, }); @@ -66,18 +112,14 @@ export function useZachetCardController(props: UseZachetCardControllerProps) { }); watch( - resolvedUserId, - (nextUserId, prevUserId) => { - logZachetCardController('resolvedUserId changed', { - prevUserId, - nextUserId, - }); - - if (nextUserId && nextUserId !== prevUserId) { + () => props.userId, + nextUserId => { + if (nextUserId) { + logZachetCardController('props.userId changed', { nextUserId }); + resolvedUserId.value = nextUserId; void load(); } - }, - { immediate: false } + } ); return { @@ -100,3 +142,16 @@ function logZachetCardController(message: string, payload?: unknown) { console.log('[ZachetCard][controller]', message, payload); } + +function errorZachetCardController(message: string, payload?: unknown) { + if (!import.meta.env.DEV) { + return; + } + + if (payload === undefined) { + console.error('[ZachetCard][controller]', message); + return; + } + + console.error('[ZachetCard][controller]', message, payload); +} From e4f50b0d429d072c001f56fdddd040d968c963a9 Mon Sep 17 00:00:00 2001 From: Dmatrushka19 Date: Sun, 26 Apr 2026 21:44:11 +0300 Subject: [PATCH 09/15] =?UTF-8?q?=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA?= =?UTF-8?q?=D1=83=20=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D0=B0=20=D0=BE=D1=82=20?= =?UTF-8?q?=D1=80=D1=83=D1=87=D0=BA=D0=B8,=20=D1=81=D0=BE=D0=B3=D0=BB?= =?UTF-8?q?=D0=B0=D1=81=D0=BD=D0=BE=20=D0=BF=D1=80=D0=BE=D0=B4=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/ZachetCard/controller/mapper.ts | 81 +++++++++++++++++---- 1 file changed, 68 insertions(+), 13 deletions(-) diff --git a/src/modules/ZachetCard/controller/mapper.ts b/src/modules/ZachetCard/controller/mapper.ts index 845539c..7a2b2fc 100644 --- a/src/modules/ZachetCard/controller/mapper.ts +++ b/src/modules/ZachetCard/controller/mapper.ts @@ -10,40 +10,95 @@ function normalizeValue(value?: string | null): string | null { return trimmed.length ? trimmed : null; } -function getValue(items: UserdataItem[], category: string, param: string): string | null { - const item = items.find(entry => entry.category === category && entry.param === param); +function getValues(items: UserdataItem[], category: string, param: string): string[] { + return items + .filter(entry => entry.category === category && entry.param === param) + .map(entry => normalizeValue(entry.value)) + .filter((value): value is string => Boolean(value)); +} - return normalizeValue(item?.value); +function getFirstValue(items: UserdataItem[], category: string, param: string): string | null { + return getValues(items, category, param)[0] ?? null; +} + +function formatDate(value: string | null): string { + if (!value) return FALLBACK; + + if (/^\d{2}\.\d{2}\.\d{4}$/.test(value)) { + return value; + } + + if (/^\d{4}-\d{2}-\d{2}$/.test(value)) { + const [year, month, day] = value.split('-'); + return `${day}.${month}.${year}`; + } + + return value; } function resolveUnionCardNumber(items: UserdataItem[]): string { return ( - getValue(items, 'Учёба', 'Номер профсоюзного билета') ?? - getValue(items, 'Учетные данные', 'Номер профсоюзного билета') ?? + getFirstValue(items, 'Учёба', 'Номер профсоюзного билета') ?? + getFirstValue(items, 'Учетные данные', 'Номер профсоюзного билета') ?? FALLBACK ); } function resolvePhotoUrl(items: UserdataItem[]): string | undefined { - const value = getValue(items, 'Личная информация', 'Фото'); + const value = getFirstValue(items, 'Личная информация', 'Фото'); if (!value) return undefined; return value; } +function resolveFacultyRu(items: UserdataItem[]): string { + const facultyValues = getValues(items, 'Учёба', 'Факультет'); + + for (const value of facultyValues) { + if (!value.includes('/')) { + return value; + } + } + + const combinedValue = facultyValues[0]; + + if (combinedValue?.includes('/')) { + return combinedValue.split('/')[0]?.trim() || FALLBACK; + } + + return combinedValue ?? FALLBACK; +} + +function resolveFacultyEn(items: UserdataItem[]): string { + const directFacultyEn = getFirstValue(items, 'Учёба', 'Faculty'); + + if (directFacultyEn) { + return directFacultyEn; + } + + const facultyValues = getValues(items, 'Учёба', 'Факультет'); + const combinedValue = facultyValues.find(value => value.includes('/')); + + if (combinedValue) { + return combinedValue.split('/')[1]?.trim() || FALLBACK; + } + + return FALLBACK; +} + export function mapUserdataToZachetCard(items: UserdataItem[]): ZachetCardData { logZachetCardMapper('start mapping items', { items }); const mappedCard: ZachetCardData = { unionCardNumber: resolveUnionCardNumber(items), - fullNameRu: getValue(items, 'Личная информация', 'Полное имя') ?? FALLBACK, - fullNameEn: FALLBACK, - birthDate: getValue(items, 'Личная информация', 'Дата рождения') ?? FALLBACK, - facultyRu: getValue(items, 'Учёба', 'Факультет') ?? FALLBACK, - facultyEn: FALLBACK, - statusRu: getValue(items, 'Учёба', 'Ступень обучения') ?? FALLBACK, - statusEn: FALLBACK, + fullNameRu: getFirstValue(items, 'Личная информация', 'Полное имя') ?? FALLBACK, + fullNameEn: getFirstValue(items, 'Личная информация', 'Full name') ?? FALLBACK, + birthDate: formatDate(getFirstValue(items, 'Личная информация', 'Дата рождения')), + facultyRu: resolveFacultyRu(items), + facultyEn: resolveFacultyEn(items), + statusRu: getFirstValue(items, 'Учёба', 'Должность') ?? FALLBACK, + statusEn: '-', photoUrl: resolvePhotoUrl(items), }; From c18d8534484d14fd9d67afa81088740a9b020706 Mon Sep 17 00:00:00 2001 From: Dmatrushka19 Date: Thu, 30 Apr 2026 13:32:36 +0300 Subject: [PATCH 10/15] =?UTF-8?q?=D0=B8=D0=B7=D0=BE=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B0=20=D0=BE=D0=B1?= =?UTF-8?q?=D0=BE=D1=80=D0=BE=D1=82=D0=BD=D0=BE=D0=B9=20=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=BE=D0=BD=D0=B5=20=D0=BA=D0=B0=D1=80=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ZachetCard/assets/mguLogoProfUnion.webp | Bin 0 -> 1006 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/modules/ZachetCard/assets/mguLogoProfUnion.webp diff --git a/src/modules/ZachetCard/assets/mguLogoProfUnion.webp b/src/modules/ZachetCard/assets/mguLogoProfUnion.webp new file mode 100644 index 0000000000000000000000000000000000000000..f15171998df6c0a55814e0541b7273ec0669dd73 GIT binary patch literal 1006 zcmV)JQ%qHPUeIHq!PyYoufO(n#mC+(%oP7COft|7Kvf^}lmlF8s4F(BE;rN_#yJT4`fS4t-{`>0W=UO&vvq+{4kUD? zQH~6wdMndW+foKbG<2X52A2#jM|`Lq-5T_MTr3QI*0T?}C>H*D>&q`)1W1hT79mdu>+jZK!=b`sKViGu@x%;mnxFJUVKf^Iu+n+I6+Ws`ZE#u@frbub0pD|AT&ajU>?Tn$);xp!Xagh{v7wwG{ z4waVTn59R!R5!sCTkmFml#YgTG#~r%xAT+|Hn6)FW2MDZ%*(!qKND2IA!EmO;nPE0 z;qU6Y#%BvO!eZsYd74G>*s)`M{Tr>Z3t1r#mPvY=r=+0OGg`UKm)Z&Fe(rvfd*tY= zYiay!XBxRcQz?}FcAj{ZGrhQ9(g&O)shpkkAB&_Gdh1@GdAL(nb=i|FFMN}WHGyIW zUv*P`(?~DoOL~!;B-OFK{$_iriN3m@DWkGtyv0o~bE(Eq=AfJ5EqPFxAn7Cu zk~M>df%=1;qz3xw4sM=9*F1-`vg)j-i~2ps6&gl`Q}1TBk1RcmCnYI)CI388!@bgP z>?+kVP`7cX9;YD3mRwTnlk_B4X$V!efh#M>m5T+T_Oofo!{sf@FOc*^?)K96xdU`| z?xo84H1|wf!skERF3&wp{c?Y_1y-#6V6Yo!Sx#1tgE{yAU~OSxVc|#G@&*7_P&god z0001x2LPP`Dpmkh06t9~j6@=#p%`=kC Date: Thu, 30 Apr 2026 13:33:10 +0300 Subject: [PATCH 11/15] =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B6=D0=BA=D0=B0=20=D0=BA=D0=BE=D0=BD=D1=82=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=BD=D0=B0=20=D0=BE=D0=B1=D0=BE=D1=80=D0=BE?= =?UTF-8?q?=D1=82=D0=BD=D0=BE=D0=B9=20=D1=81=D1=82=D0=BE=D1=80=D0=BE=D0=BD?= =?UTF-8?q?=D0=B5=20=D0=BA=D0=B0=D1=80=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/ZachetCard/controller/mapper.ts | 9 +++++++++ src/modules/ZachetCard/controller/types.ts | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/modules/ZachetCard/controller/mapper.ts b/src/modules/ZachetCard/controller/mapper.ts index 7a2b2fc..daf71a1 100644 --- a/src/modules/ZachetCard/controller/mapper.ts +++ b/src/modules/ZachetCard/controller/mapper.ts @@ -2,6 +2,14 @@ import type { UserdataItem, ZachetCardData } from './types'; const FALLBACK = '—'; +const DEFAULT_CONTACTS = { + address: '1018а, Главное здание МГУ', + phone: '+7 (495)-939-14-58', + email: 'begomvprofcom@mail.ru', + vk: '@msuprofcom', + website: 'msuprof.com', +}; + function normalizeValue(value?: string | null): string | null { if (typeof value !== 'string') return null; @@ -100,6 +108,7 @@ export function mapUserdataToZachetCard(items: UserdataItem[]): ZachetCardData { statusRu: getFirstValue(items, 'Учёба', 'Должность') ?? FALLBACK, statusEn: '-', photoUrl: resolvePhotoUrl(items), + contacts: DEFAULT_CONTACTS, }; logZachetCardMapper('mapped card result', mappedCard); diff --git a/src/modules/ZachetCard/controller/types.ts b/src/modules/ZachetCard/controller/types.ts index 810a31e..9cea707 100644 --- a/src/modules/ZachetCard/controller/types.ts +++ b/src/modules/ZachetCard/controller/types.ts @@ -8,6 +8,14 @@ export interface UserdataResponse { items: UserdataItem[]; } +export interface ZachetCardContacts { + address: string; + phone: string; + email: string; + vk: string; + website: string; +} + export interface ZachetCardData { unionCardNumber: string; fullNameRu: string; @@ -18,4 +26,5 @@ export interface ZachetCardData { statusRu: string; statusEn: string; photoUrl?: string; + contacts: ZachetCardContacts; } From b52a0d804abaad39d24c76d8ccc50effc0799831 Mon Sep 17 00:00:00 2001 From: Dmatrushka19 Date: Thu, 30 Apr 2026 13:33:31 +0300 Subject: [PATCH 12/15] =?UTF-8?q?=D0=B2=D1=8B=D0=BD=D0=B5=D1=81=20=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D1=81=D1=82=D0=BA=D1=83=20=D0=BB=D0=B8=D1=86=D0=B5?= =?UTF-8?q?=D0=B2=D0=BE=D0=B9=20=D1=81=D1=82=D0=BE=D1=80=D0=BE=D0=BD=D1=8B?= =?UTF-8?q?=20=D0=BA=D0=B0=D1=80=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/ZachetCard/ui/ZachetCardFront.vue | 243 ++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 src/modules/ZachetCard/ui/ZachetCardFront.vue diff --git a/src/modules/ZachetCard/ui/ZachetCardFront.vue b/src/modules/ZachetCard/ui/ZachetCardFront.vue new file mode 100644 index 0000000..5e612d7 --- /dev/null +++ b/src/modules/ZachetCard/ui/ZachetCardFront.vue @@ -0,0 +1,243 @@ + + + + + From 9c79cdd9d4915e0959bbef246f008b525dd13c05 Mon Sep 17 00:00:00 2001 From: Dmatrushka19 Date: Thu, 30 Apr 2026 13:33:42 +0300 Subject: [PATCH 13/15] =?UTF-8?q?=D0=B2=D1=8B=D0=BD=D0=B5=D1=81=20=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D1=81=D1=82=D0=BA=D1=83=20=D0=BE=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D1=82=D0=BD=D0=BE=D0=B9=20=D1=81=D1=82=D0=BE=D1=80=D0=BE?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BA=D0=B0=D1=80=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/ZachetCard/ui/ZachetCardBack.vue | 336 +++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 src/modules/ZachetCard/ui/ZachetCardBack.vue diff --git a/src/modules/ZachetCard/ui/ZachetCardBack.vue b/src/modules/ZachetCard/ui/ZachetCardBack.vue new file mode 100644 index 0000000..41757d3 --- /dev/null +++ b/src/modules/ZachetCard/ui/ZachetCardBack.vue @@ -0,0 +1,336 @@ + + + + + From 567d3268bd20ca0aa796468305f6b3959f7c147a Mon Sep 17 00:00:00 2001 From: Dmatrushka19 Date: Thu, 30 Apr 2026 13:33:57 +0300 Subject: [PATCH 14/15] =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B6=D0=BA=D0=B0=20=D0=B4=D0=B2=D1=83=D1=85=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=BE=D0=BD=D0=BD=D0=B5=D0=B9=20=D0=BA=D0=B0=D1=80=D1=82?= =?UTF-8?q?=D1=8B=20=D1=81=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=BE=D0=B9=20?= =?UTF-8?q?"=D0=BF=D0=B5=D1=80=D0=B5=D0=B2=D0=B5=D1=80=D0=BD=D1=83=D1=82?= =?UTF-8?q?=D1=8C"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/ZachetCard/ZachetCard.vue | 284 ++++++++------------------ 1 file changed, 83 insertions(+), 201 deletions(-) diff --git a/src/modules/ZachetCard/ZachetCard.vue b/src/modules/ZachetCard/ZachetCard.vue index 3751e60..d11a47d 100644 --- a/src/modules/ZachetCard/ZachetCard.vue +++ b/src/modules/ZachetCard/ZachetCard.vue @@ -1,18 +1,46 @@