Browse Source

DEV: 06 04 2025

#24
Morozov Vadim 4 months ago
parent
commit
b1b06d2848

+ 5 - 2
capacitor.config.ts

@@ -8,9 +8,12 @@ const config: CapacitorConfig = {
   backgroundColor: '#323232',
   plugins: {
     SplashScreen: {
-      launchShowDuration: 2000,
+      launchShowDuration: 3000,
       backgroundColor: "#323232",
-      showSpinner: false,
+      showSpinner: true,
+      androidSpinnerStyle: "small",
+      iosSpinnerStyle: "small",
+      spinnerColor: "#212121",
       splashFullScreen: true,
       splashImmersive: true,
     },

+ 6 - 2
components/Base/Header.vue

@@ -1,7 +1,9 @@
 <template>
   <header
-    class="w-full flex justify-between gap-5 bg-background-100 p-3 animate__animated animate__fadeInDown animate__faster z-10"
+  class="w-full flex justify-between gap-5 bg-background-100 p-3 animate__animated animate__fadeInDown animate__faster z-10"
   >
+    <NuxtLoadingIndicator class="w-full" :height="2" color="#e5e7eb" />
+    
     <ISandwich
       class="w-8 h-8 hover:opacity-50 cursor-pointer duration-150"
       @click="sideBar.show()"
@@ -71,9 +73,11 @@ function hide() {
   setTimeout(() => {
     showMenu.value = false
   }, 100)
+  updateColors('#212121')
 }
 function show() {
   showMenu.value = true
   showAnim.value = true
+  updateColors('#171717')
 }
-</script>
+</script>

+ 51 - 14
components/Base/SideBar/element.vue

@@ -318,28 +318,65 @@
         />
       </svg>
 
+      <svg
+        v-else-if="type === 'contacts'"
+        width="37"
+        height="48"
+        viewBox="0 0 48 48"
+        fill="none"
+        xmlns="http://www.w3.org/2000/svg"
+      >
+        <path
+          d="M6 24.0002C6 9.17718 9.177 6.00018 24 6.00018C38.823 6.00018 42 9.17718 42 24.0002C42 38.8232 38.823 42.0002 24 42.0002C9.177 42.0002 6 38.8232 6 24.0002Z"
+          :stroke="color"
+          stroke-width="4"
+        />
+        <path
+          d="M30 20.0002C30 23.314 27.3138 26.0002 24 26.0002C20.6862 26.0002 18 23.314 18 20.0002C18 16.6865 20.6862 14.0002 24 14.0002C27.3138 14.0002 30 16.6865 30 20.0002Z"
+          :stroke="color"
+          stroke-width="4"
+        />
+        <path
+          d="M12 38.0002C13.2764 33.3858 16.56 32.0002 24 32.0002C31.44 32.0002 34.7236 33.2852 36 37.8996"
+          :stroke="color"
+          stroke-width="4"
+          stroke-linecap="round"
+        />
+      </svg>
+
       <p
         class="text-lg font-semibold duration-150"
         :style="`color: ${color};`"
         v-text="$props.text"
       />
-      <p
-        class="ml-auto"
-        v-text="count"
-      />
+      <p class="ml-auto" v-text="count" />
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
-withDefaults(defineProps<{
-  type?: 'home' | 'license' | 'calendar' | 'mail' | 'bell' | 'photo' | 'chart' | 'cog' | 'alert-circle' | 'logout'
-  text?: string
-  count?: number
-  color?: string
-}>(), {
-  type: 'home',
-  text: 'Новости',
-  color: '#EDE8D8',
-})
+withDefaults(
+  defineProps<{
+    type?:
+      | "home"
+      | "license"
+      | "calendar"
+      | "mail"
+      | "bell"
+      | "photo"
+      | "chart"
+      | "cog"
+      | "alert-circle"
+      | "logout"
+      | "contacts";
+    text?: string;
+    count?: number;
+    color?: string;
+  }>(),
+  {
+    type: "home",
+    text: "Новости",
+    color: "#EDE8D8",
+  }
+);
 </script>

+ 7 - 2
components/Base/SideBar/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="store.isRendered"
+    v-show="store.isRendered"
     ref="sideBarEl"
     class="w-screen h-screen fixed top-0 left-0 z-30"
   >
@@ -131,7 +131,7 @@ const user = useUser()
 
 const links = ref<{
   name: string
-  icon: 'home' | 'license' | 'calendar' | 'mail' | 'bell' | 'photo' | 'chart'
+  icon: 'home' | 'license' | 'calendar' | 'mail' | 'bell' | 'photo' | 'chart' | 'contacts'
   route: string
 }[]>([
   {
@@ -159,6 +159,11 @@ const links = ref<{
   //   icon: 'bell',
   //   route: '/notifications',
   // },
+  {
+    name: 'Контакты',
+    icon: 'contacts',
+    route: '/contacts'
+  },
   {
     name: 'Галерея',
     icon: 'photo',

+ 33 - 0
components/Contact/Item.vue

@@ -0,0 +1,33 @@
+<template>
+    <div class="flex flex-col gap-1 justify-center items-center text-center bg-black bg-opacity-20 rounded-md p-1">
+        <p class="text-xl font-semibold" v-text="contact.full_name" />
+        <p class="text-sm" v-text="contact.post" />
+        <a :href="`mailto:${contact.email}`" v-text="`Почта: ${contact.email}`" />
+        <div>
+            <p v-text="`Телефон${ contact.phones.length > 1 ? 'ы' : '' }:`" />
+            <p 
+                v-for="(phone, idx) in contact.phones" 
+                :key="idx" 
+                v-text="phone"
+            />
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts">
+interface TContact {
+    address: string;
+    email: string;
+    full_name: string;
+    phones: string[];
+    post: string;
+}
+
+defineProps<{
+    contact: TContact
+}>()
+</script>
+
+<style scoped>
+
+</style>

+ 1 - 1
components/Wall/Post.vue

@@ -3,7 +3,7 @@
     <img
       :src="$props.image"
       :alt="'Возникла проблема с загрузкой фото, попробуйте позже.'"
-      class="h-[170px] object-cover object-center"
+      class="h-[250px] object-cover object-center"
     >
     <div class="px-2 leading-none text-xl font-semibold">
       {{ $props.title }}

+ 15 - 14
pages/blog/index.vue

@@ -6,7 +6,7 @@
       </button>
     </NuxtLink> -->
     <div
-      v-if="!postList"
+      v-show="postList?.items.length === 0"
       class="w-full h-full"
     >
       <div
@@ -16,18 +16,17 @@
         class="w-full h-32 loading rounded-md opacity-30"
       />
     </div>
-    <template v-else>
-      <BlogPost
-        v-for="(post, idx) in postList.items"
-        :key="idx"
-        :avatar="post.avatar"
-        :title="post.title"
-        :raw_content="post.raw_content"
-        :date="post.date"
-        :author="post.author"
-        :attachments="post.attachments"
-      />
-    </template>
+    <BlogPost
+      v-show="postList?.items.length > 0"
+      v-for="(post, idx) in postList.items"
+      :key="idx"
+      :avatar="post.avatar"
+      :title="post.title"
+      :raw_content="post.raw_content"
+      :date="post.date"
+      :author="post.author"
+      :attachments="post.attachments"
+    />
   </div>
 </template>
 
@@ -40,7 +39,9 @@ definePageMeta({
 })
 
 const { $api } = useNuxtApp()
-const postList = ref<TPosts>()
+const postList = ref<TPosts>({
+  items: []
+})
 
 onMounted(async () => {
   postList.value = await $api.blog.getPosts()

+ 36 - 0
pages/contacts.vue

@@ -0,0 +1,36 @@
+<template>
+    <div
+      class="w-full h-full flex flex-col gap-5 p-2"
+    >
+      <div
+        v-show="!contactsList"
+        v-for="i of Array.from({ length: 5 }).map((i, idx) => idx)"
+        :key="i"
+        :class="i === 0 ? 'mt-0 mb-4' : 'my-4'"
+        class="w-full h-[200px] loading rounded-md opacity-30"
+      />
+      <ContactItem
+        v-for="(contact, idx) in contactsList" 
+        :key="idx"
+        :contact="contact"
+      />
+    </div>
+</template>
+
+<script setup lang="ts">
+const { $api } = useNuxtApp()
+const contactsList = ref()
+
+definePageMeta({
+  name: 'Контакты',
+  middleware: ['user-only'],
+})
+
+onMounted(async () => {
+  contactsList.value = await $api.contacts.getContacts()
+})
+</script>
+
+<style scoped>
+
+</style>

+ 1 - 3
pages/index.vue

@@ -9,7 +9,5 @@ definePageMeta({
   layout: 'none',
 })
 
-const router = useRouter()
-
-router.push('/auth')
+window.location.href = '/auth'
 </script>

+ 1 - 1
pages/news/[id]/index.vue

@@ -46,7 +46,7 @@
     </div>
     <div
       v-if="news"
-      class="flex flex-col min-h-screen h-[2000px] news-content"
+      class="flex flex-col min-h-screen h-[2000px] news-content overflow-y-hidden"
       :style="`padding-top: ${headerHeightMax}px`"
       v-html="news.content"
     />

+ 5 - 5
pages/timetable/index.vue

@@ -1,16 +1,16 @@
 <template>
   <div
-    v-if="!timetable"
+    v-show="!timetable"
     class="w-full h-full flex items-center justify-center show"
   >
     <ILoader class="w-16 h-16 text-foreground" />
   </div>
   <div
-    v-else
+    v-if="timetable"
     class="flex flex-col gap-2 show py-4 h-full"
   >
     <div
-      v-if="week"
+      v-show="week"
       class="grid grid-cols-3 place-items-center mb-5"
     >
       <img
@@ -31,7 +31,7 @@
         @click="nextWeek"
       >
     </div>
-    <template v-if="hasLessons">
+    <template v-show="hasLessons">
       <div
         v-for="(day, dayIdx) in timetable.days"
         :key="day.title"
@@ -91,7 +91,7 @@
       </div>
     </template>
     <div
-      v-else
+      v-show="!hasLessons"
       class="w-full h-full flex items-center justify-center"
     >
       <p class="text-2xl font-semibold text-center">

+ 3 - 0
plugins/api.client.ts

@@ -5,6 +5,7 @@ import BranchModule from '@/repository/modules/branch'
 import TimetableModule from '@/repository/modules/timetable'
 import BlogModule from '@/repository/modules/blog'
 import NewsModule from '@/repository/modules/news'
+import ContactsModule from '~/repository/modules/contacts'
 
 export interface IApiInstance {
   user: UserModule
@@ -14,6 +15,7 @@ export interface IApiInstance {
   timetable: TimetableModule
   blog: BlogModule
   news: NewsModule
+  contacts: ContactsModule
 }
 
 export interface Provide {
@@ -34,6 +36,7 @@ export default defineNuxtPlugin(() => {
     timetable: new TimetableModule('TimetableModule'),
     blog: new BlogModule('BlogModule'),
     news: new NewsModule('NewsModule'),
+    contacts: new ContactsModule('ContactsModule'),
   }
 
   return {

+ 2 - 6
release.config.cjs

@@ -12,10 +12,6 @@ module.exports = {
       name: 'dev',
       prerelease: 'dev',
     },
-    {
-      name: 'pre-dev',
-      prerelease: 'pre-dev',
-    },
   ],
   plugins: [
     '@semantic-release/commit-analyzer',
@@ -34,8 +30,8 @@ module.exports = {
       {
         assets: [
           {
-            path: '${nextRelease.version}.apk',
-            label: 'Android APK [${nextRelease.version}]',
+            path: `${process.env.APP_VERSION}.apk`,
+            label: `Android APK [${process.env.APP_VERSION}]`,
           },
         ],
       },

+ 4 - 3
repository/api.ts

@@ -24,7 +24,6 @@ export class API {
   private module: string = 'API'
   private API_URL: string = useRuntimeConfig().public.API_URL
   private user = useUser()
-  private snackbar = useSnackbar()
 
   constructor(module: string) {
     this.module = module
@@ -32,11 +31,13 @@ export class API {
   }
 
   private throwError(request: string, data: TException, body?: unknown) {
+    const snackbar = useSnackbar()
     const err = {
       info: '',
       request,
       body,
     }
+
     if (Object.prototype.hasOwnProperty.call(data, 'code') && Object.prototype.hasOwnProperty.call(data, 'error')) {
       err.info = `${data.error} (${data.code})`
     }
@@ -49,7 +50,7 @@ export class API {
     }
 
     this.log.error(err)
-    this.snackbar.add({
+    snackbar.add({
       type: 'error',
       text: 'Возникла ошибка на сервере. Не переживайте, мы уже знаем о проблеме 👌'
     })
@@ -64,7 +65,7 @@ export class API {
     },
     onResponse: (ctx) => {
       const statusCode = ctx.response.status
-      if (statusCode > 300 && statusCode !== 400) {
+      if (statusCode > 300 && statusCode !== 400 && statusCode !== 401) {
         this.throwError(ctx.request.toString(), ctx.response._data, ctx.options.body)
       }
     },

+ 12 - 0
repository/modules/contacts.ts

@@ -0,0 +1,12 @@
+import { API } from '../api'
+
+class ContactsModule extends API {
+  // TODO: types
+  async getContacts() {
+    return await this.get<object>(
+      `/contacts/`,
+    )
+  }
+}
+
+export default ContactsModule