feat(app): tests

This commit is contained in:
vbuglov 2024-04-01 09:37:52 +03:00
parent eefc7ba4ac
commit 2b37e59afc
46 changed files with 1101 additions and 693 deletions

View File

@ -26,6 +26,7 @@
<link rel="stylesheet" href="/css/components/media.css"> <link rel="stylesheet" href="/css/components/media.css">
<link rel="stylesheet" href="/css/components/menu.css"> <link rel="stylesheet" href="/css/components/menu.css">
<link rel="stylesheet" href="/css/_flatpickr.css"> <link rel="stylesheet" href="/css/_flatpickr.css">
<link rel="stylesheet" href="/css/animation.css">
<title>LiveMonitor</title> <title>LiveMonitor</title>
</head> </head>
<body> <body>

View File

@ -0,0 +1,92 @@
/* Определение анимации */
@keyframes slide-left {
from {
transform: translateX(-100vw); /* Старт с -100% по оси X, чтобы меню было скрыто */
opacity: 0; /* Начальная прозрачность для плавного появления */
}
to {
transform: translateX(0vw); /* Конечное положение: на месте */
opacity: 1; /* Полная видимость */
}
}
@keyframes appear-opacity {
from {
opacity: 0; /* Начальная прозрачность для плавного появления */
}
to {
opacity: 1; /* Полная видимость */
}
}
.appear-opacity-100 {
animation: appear-opacity 0.1s ease-out forwards;
}
.appear-opacity-200 {
animation: appear-opacity 0.2s ease-out forwards;
}
.appear-opacity-300 {
animation: appear-opacity 0.3s ease-out forwards;
}
.appear-opacity-400 {
animation: appear-opacity 0.4s ease-out forwards;
}
.appear-opacity-500 {
animation: appear-opacity 0.5s ease-out forwards;
}
.appear-opacity-600 {
animation: appear-opacity 0.6s ease-out forwards;
}
.appear-opacity-700 {
animation: appear-opacity 0.7s ease-out forwards;
}
.appear-opacity-800 {
animation: appear-opacity 0.8s ease-out forwards;
}
.appear-opacity-900 {
animation: appear-opacity 0.9s ease-out forwards;
}
.slide-left-100 {
animation: slide-left 0.1s ease-out forwards;
}
.slide-left-200 {
animation: slide-left 0.2s ease-out forwards;
}
.slide-left-300 {
animation: slide-left 0.3s ease-out forwards;
}
.slide-left-400 {
animation: slide-left 0.4s ease-out forwards;
}
.slide-left-500 {
animation: slide-left 0.5s ease-out forwards;
}
.slide-left-600 {
animation: slide-left 0.6s ease-out forwards;
}
.slide-left-700 {
animation: slide-left 0.7s ease-out forwards;
}
.slide-left-800 {
animation: slide-left 0.8s ease-out forwards;
}
.slide-left-900 {
animation: slide-left 0.9s ease-out forwards;
}

View File

@ -1,11 +1,12 @@
<script> <script>
import MenuList from './MenuList.vue' import MenuList from './MenuList/MenuList.vue'
import MobileMenu from './MobileMenu.vue' import MobileMenu from './AppContainerMobileMenu.vue'
import LeftPanel from './AppContainerLeftPanel.vue' import LeftPanel from './AppContainerLeftPanel.vue'
import Breadcrumbs from './AppContainerBreadcrumbs.vue' import Breadcrumbs from './AppContainerBreadcrumbs.vue'
import RightPanel from './RightPanel.vue' import RightPanel from './AppContainerRightPanel.vue'
import AppContainerHeader from './AppContainerHeader.vue' import AppContainerHeader from './AppContainerHeader.vue'
import {mapGetters} from 'vuex' import {mapGetters} from 'vuex'
import ServiceOfLayout from '@services/ServiceOfLayout'
export default { export default {
name: 'AppContainer', name: 'AppContainer',
@ -18,41 +19,91 @@ export default {
AppContainerHeader AppContainerHeader
}, },
data() { data() {
return {
serviceOfLayout: null,
isOpenedMobileMenu: false,
routeName: ""
}
}, },
computed: { computed: {
...mapGetters('layout', ["show_menu", 'is_enabled_menu']), ...mapGetters('layout', ["isShowMenu", 'isEnabledMenu']),
...mapGetters('auth', ['menuList']), ...mapGetters('auth', ['menuList', 'currentUser']),
menuListWithIndex() {
return this.menuList.map((el, index) => ({...el, index}))
}
},
watch:{
$route (to){
this.routeName = to.name;
this.closeMobileMenu()
}
},
mounted() {
const store = this.$store
this.serviceOfLayout = new ServiceOfLayout(store)
}, },
methods: { methods: {
closeMobileMenu() {
this.isOpenedMobileMenu = false
},
openMobileMenu() {
this.isOpenedMobileMenu = true
},
setIsMobileMenuOpened(isOpened) {
if (this.serviceOfLayout) {
this.serviceOfLayout.setIsMobileMenuOpened(isOpened)
}
},
toggleMenu() {
if (this.serviceOfLayout) {
this.serviceOfLayout.toggleMenu()
}
},
toggleMobileMenu() {
if (this.isOpenedMobileMenu) {
this.closeMobileMenu()
} else {
this.openMobileMenu()
}
}
} }
} }
</script> </script>
<template> <template>
<div class="main w-full"> <div
v-if="serviceOfLayout"
class="main w-full"
>
<!-- BEGIN: TOP BAR --> <!-- BEGIN: TOP BAR -->
<div <div
id="menu" id="menu"
class="top-bar-boxed w-full h-[59px] mt-[4px] z-[51] relative justify-center border-b border-white/[0.2] -mx-3 px-3 sm:pl-8 md:pt-0 mb-[4px]" class="top-bar-boxed w-full h-[59px] mt-[4px] z-[51] relative justify-center border-b border-white/[0.2] -mx-3 px-3 sm:pl-8 md:pt-0 mb-[4px]"
> >
<MobileMenu <MobileMenu
v-if="false" v-if="isOpenedMobileMenu"
current_menu_item="" :menuListWithIndex="menuListWithIndex"
current_user="" currentMenuItem="routeName"
:menu_list="menuList" :currentUser="currentUser"
setIsMobileMenuOpened="setIsMobileMenuOpened"
:toggleMobileMenu="toggleMobileMenu"
/> />
<AppContainerHeader> <AppContainerHeader>
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<LeftPanel /> <LeftPanel
:toggleMobileMenu="toggleMobileMenu"
/>
<Breadcrumbs <Breadcrumbs
v-if="false" v-if="false"
:breadcrumbs="[]" :breadcrumbs="[]"
/> />
<RightPanel <RightPanel
:current_user="''" :current_user="''"
:page_title="''" :pageTitle="''"
:toggleMenu="toggleMenu"
:notifications="[{from: 'Бот из LM', datetime: '10:00', message: 'Проведен редизайн приложения', readed: false}]" :notifications="[{from: 'Бот из LM', datetime: '10:00', message: 'Проведен редизайн приложения', readed: false}]"
:currentUser="currentUser"
/> />
</div> </div>
<div class="sm:hidden flex items-center justify-between" /> <div class="sm:hidden flex items-center justify-between" />
@ -61,9 +112,11 @@ export default {
<!-- END: TOP BAR --> <!-- END: TOP BAR -->
<div class="wrapper"> <div class="wrapper">
<div class="wrapper-box"> <div class="wrapper-box">
<div v-if="show_menu && is_enabled_menu"> <div v-if="isShowMenu && isEnabledMenu">
<MenuList <MenuList
:menu_list="menuList" :isShowMenu="isShowMenu"
:menuListWithIndex="menuListWithIndex"
:routeName="routeName"
/> />
</div> </div>
<div class="content"> <div class="content">

View File

@ -9,8 +9,6 @@ export default {
default: null default: null
}, },
}, },
data() {
},
computed: { computed: {
}, },
methods: { methods: {

View File

@ -1,8 +1,18 @@
<script> <script>
import { h } from 'vue'
import {createIcons, icons} from "lucide";
export default { export default {
name: 'AppContainerLeftPanel', name: 'AppContainerLeftPanel',
components: {}, components: {
MobileMenuButton: h('div')
},
props: {
toggleMobileMenu: {
type: Function,
default: () => {}
}
},
data() { data() {
return { return {
mobile_menu_opened: false mobile_menu_opened: false
@ -10,25 +20,34 @@ export default {
}, },
computed: { computed: {
}, },
mounted() {
this.icons()
},
updated() {
this.icons()
},
methods: { methods: {
} icons() {
createIcons({ icons, nameAttr: "icon" })
}
},
} }
</script> </script>
<template> <template>
<div class="flex items-center border-white/[0.2] border-r"> <div class="flex items-center border-white/[0.2] border-r">
<div <mobile-menu-button
class="flex p-4 cursor-pointer flex md:hidden" class="flex p-4 cursor-pointer md:hidden"
@click="mobile_menu_opened = !mobile_menu_opened" @click="toggleMobileMenu()"
> >
<i <i
icon="bar-chart-2" icon="bar-chart-2"
class="w-6 h-6 text-white transform rotate-90" class="w-6 h-6 text-white transform rotate-90"
/> />
</div> </mobile-menu-button>
<router-link <router-link
class="items-center relative -intro-x flex cursor-pointer p-4 hidden md:flex" class="hidden md:flex items-center relative -intro-x cursor-pointer p-4 "
to="/?page=machines&mode=cards" to="/?page=machines&mode=cards"
> >
<div <div

View File

@ -0,0 +1,60 @@
<script>
import MenuListItem from './MenuList/MenuListItem.vue'
export default {
name: 'AppContainerMobileMenu',
components: {
MenuListItem
},
props: {
currentMenuItem: {
type: String,
default: ""
},
menuListWithIndex: {
type: Array,
default: () => []
},
toggleMobileMenu: {
type: Function,
required: true,
},
},
data() {
return {}
},
methods: {
randomkey() {
return Math.random().toString(36).slice(4)
},
}
}
</script>
<template>
<div class="mobile-menu--active appear-opacity-200 mobile-menu md:hidden">
<span
class="absolute top-[30px] right-0 z-40"
@click="toggleMobileMenu()"
>
<i
icon="x-circle"
class="w-8 h-8 text-white transform -rotate-90"
/>
</span>
<div class="scrollable slide-left-400">
<ul class=" scrollable__content py-2">
<MenuListItem
v-for="{index, ...menuItem} in menuListWithIndex"
:key="randomkey(index)"
baseClass="menu"
:type="menuItem.type"
:menuItem="menuItem"
:currentMenuItem="currentMenuItem"
/>
</ul>
</div>
</div>
</template>

View File

@ -1,24 +1,30 @@
<!-- eslint-disable vue/prop-name-casing -->
<script> <script>
import {mapGetters, mapMutations} from 'vuex' import {mapGetters} from 'vuex'
import { createIcons, icons } from "lucide"; import { createIcons, icons } from "lucide";
export default { export default {
name: 'RightPanel', name: 'RightPanel',
components: {}, components: {},
props: { props: {
// eslint-disable-next-line vue/prop-name-casing pageTitle: {
page_title: {
type: String, type: String,
default: "" default: ""
},
toggleMenu: {
type: Function,
default: () => {}
},
notifications: {
type: Array,
default: () => []
},
currentUser: {
type: Object,
required: true
} }
}, },
data() { data() {
return { return { }
}
},
computed: {
...mapGetters('auth', ['current_user'])
}, },
mounted() { mounted() {
this.icons() this.icons()
@ -27,11 +33,12 @@ export default {
this.icons() this.icons()
}, },
methods: { methods: {
...mapMutations('layout', ["toggle_menu"]),
icons() { icons() {
createIcons({ icons, "stroke-width": 1.5, nameAttr: "icon" }) createIcons({
icons, "stroke-width": 1.5, nameAttr: "icon"
})
}, },
rkey() { randomkey() {
return Math.random().toString(36).slice(4) return Math.random().toString(36).slice(4)
}, },
closeDropDown() { closeDropDown() {
@ -46,9 +53,9 @@ export default {
<template> <template>
<div class="flex items-center justify-end grow gapy-2 px-4 border-hide-600"> <div class="flex items-center justify-end grow px-4 border-hide-600">
<div class=""> <div class="">
{{ page_title }} {{ pageTitle }}
</div> </div>
<div class="flex"> <div class="flex">
<div class="relative"> <div class="relative">
@ -66,7 +73,7 @@ export default {
/> />
<div <div
style="font-size: 7px; font-weight: 900; top: 10px; left: 30px" style="font-size: 7px; font-weight: 900; top: 10px; left: 30px"
class="h-[13px] w-[13px] bg-white rounded-full mr-8 transition absolute flex itens-center justify-center" class="h-[13px] w-[13px] bg-white rounded-full mr-8 transition absolute flex items-center justify-center"
> >
<span <span
style="line-height: 13px; font-weight: 900; font-size: 7px" style="line-height: 13px; font-weight: 900; font-size: 7px"
@ -81,14 +88,17 @@ export default {
</div> </div>
<div <div
v-for="{from, datetime, message, readed} in notifications" v-for="{from, datetime, message, readed} in notifications"
:key="rkey(message)" :key="randomkey(message)"
class="cursor-pointer relative flex items-center " class="cursor-pointer relative flex items-center "
> >
<div :class="{'bg-gray-400 w-3 h-3 absolute right-0 bottom-0 rounded-full border-2 border-white dark:border-darkmode-600|, else: ~s|bg-success w-3 h-3 absolute right-0 bottom-0 rounded-full border-2 border-white dark:border-darkmode-600': readed}" /> <div
:class="{'bg-gray-400 w-3 h-3 absolute right-0 bottom-0 rounded-full border-2 border-white dark:border-darkmode-600': readed,
'bg-success w-3 h-3 absolute right-0 bottom-0 rounded-full border-2 border-white dark:border-darkmode-600': !readed}"
/>
<div class="ml-2 overflow-hidden"> <div class="ml-2 overflow-hidden">
<div class="flex items-center"> <div class="flex items-center">
<a <a
href="javascript:;" href="javascript:"
class="font-medium truncate mr-5" class="font-medium truncate mr-5"
>{{ from }}</a> >{{ from }}</a>
<div class="text-xs text-slate-400 ml-auto whitespace-nowrap"> <div class="text-xs text-slate-400 ml-auto whitespace-nowrap">
@ -120,7 +130,7 @@ export default {
</div> </div>
<div <div
class="cursor-pointer hidden md:flex border-white/[0.2] border-r p-4" class="cursor-pointer hidden md:flex border-white/[0.2] border-r p-4"
@click="toggle_menu" @click="toggleMenu"
> >
<i <i
id="menu_library" id="menu_library"
@ -146,13 +156,13 @@ export default {
<ul class="dropdown-content before:block before:absolute before:bg-black before:inset-0 before:rounded-md before:z-[-1]"> <ul class="dropdown-content before:block before:absolute before:bg-black before:inset-0 before:rounded-md before:z-[-1]">
<li class="p-2"> <li class="p-2">
<div class="font-bold"> <div class="font-bold">
{{ current_user?.first_name || "" }} {{ current_user?.last_name || "" }} {{ currentUser?.first_name || "" }} {{ currentUser?.last_name || "" }}
</div> </div>
<div <div
class="text-xs text-black/60 dark:text-slate-500" class="text-xs text-black/60 dark:text-slate-500"
style="margin-top: -0.25rem;" style="margin-top: -0.25rem;"
> >
{{ current_user?.position || "позиция не указана" }} {{ currentUser?.position || "позиция не указана" }}
</div> </div>
</li> </li>
<li> <li>

View File

@ -1,119 +0,0 @@
<!-- eslint-disable vue/prop-name-casing -->
<script>
import { cond, equals, T, always } from 'ramda'
import { createIcons, icons } from "lucide";
import MenuItemGroup from './MenuItemGroup.vue'
export default {
name: 'MenuItem',
components: {MenuItemGroup},
props: {
type: {
type: String,
default: null
},
menu_item: {
type: Object,
default: () => ({
link: "/"
})
},
base_class: {
type: String,
default: ""
},
routeName: {
type: String,
default: ""
}
},
data() {
},
computed: {
_base_class() {
return `${this.base_class}`
},
activeClass () {
return 'side-menu side-menu--active'
},
menuRouterName() {
return this.menu_item.router || ""
},
currentRouterName() {
return this.$router.currentRoute._value.name || ""
},
linkClass() {
const menuRouterName = this.menu_item.router || ""
if (menuRouterName === this.routeName)
return `${this._base_class} ${this._base_class}--active`
return this._base_class
},
_type() {
return cond([
[equals("simple_link"), (x) => x],
[equals("line"), (x) => x],
[equals("group"), (x) => x],
[T, () => "other"],
])(this.type)
}
},
mounted() {
this.icons()
},
updated() {
console.log(123)
this.icons()
},
methods: {
icons() {
createIcons({ icons, "stroke-width": 1.5, nameAttr: "icon" })
}
}
}
</script>
<template>
<li v-if="_type == 'simple_link'">
<router-link
phx-hook="MenuLink"
:class="linkClass"
:to="menu_item.link"
>
<div :class="`${_base_class}__icon`">
<i :icon="menu_item?.icon" />
</div>
<div :class="`${_base_class}__title`">
{{ menu_item.show }}
</div>
</router-link>
</li>
<li v-if="_type == 'line'">
<hr class="m-4">
</li>
<MenuItemGroup
v-if="_type == 'group'"
:type="_type"
:base_class="base_class"
:menu_item="menu_item"
/>
<div v-if="_type == 'other'">
""
</div>
</template>
<!-- <router-link
v-if="type === 'link'"
class="flex p-2 rounded-md hover:bg-gray-100 flex items-center"
:class="{'bg-gray-200': pageName === name}"
:to="link"
>
<i :class="`ri-${icon} text-slate-600 mr-2 `" />
<span
v-if="isOpenMenu"
class="text-slate-700"
>{{ title }}</span>
</router-link> -->

View File

@ -1,93 +0,0 @@
<!-- eslint-disable vue/prop-name-casing -->
<script>
import { cond, equals, T } from 'ramda'
import { createIcons, icons } from "lucide";
export default {
name: 'MenuItemCopy',
components: {},
props: {
type: {
type: String,
default: null
},
menu_item: {
type: Object,
default: () => ({
link: "/"
})
},
base_class: {
type: String,
default: ""
}
},
data() {
},
computed: {
_base_class() {
return `${this.base_class}`
},
activeClass () {
return 'side-menu side-menu--active'
},
menuRouterName() {
return this.menu_item.router || ""
},
currentRouterName() {
return this.$router.currentRoute._value.name || ""
},
linkClass() {
const menuRouterName = this.menu_item.router || ""
const currentRouterName = this.$router.currentRoute._value.name || Math.random()
if (menuRouterName === currentRouterName)
return `${this._base_class} ${this._base_class}--active`
return this._base_class
},
_type() {
return cond([
[equals("simple_link"), (x) => x],
[equals("line"), (x) => x],
[equals("group"), (x) => x],
[T, () => "other"],
])(this.type)
}
},
mounted() {
this.icons()
},
updated() {
this.icons()
},
methods: {
icons() {
createIcons({ icons, "stroke-width": 1.5, nameAttr: "icon" })
}
}
}
</script>
<template>
<li v-if="_type == 'simple_link'">
<router-link
phx-hook="MenuLink"
:class="linkClass"
:to="menu_item.link"
>
<div :class="`${_base_class}__icon`">
<i :icon="menu_item?.icon" />
</div>
<div :class="`${_base_class}__title`">
{{ menu_item.show }}
</div>
</router-link>
</li>
<li v-if="_type == 'line'">
<hr class="m-4">
</li>
<div v-if="_type == 'other'">
""
</div>
</template>

View File

@ -1,80 +0,0 @@
<!-- eslint-disable vue/prop-name-casing -->
<script>
import MenuItem from './MenuItemCopy.vue'
export default {
name: 'MenuItemGroup',
components: {
MenuItem
},
props: {
type: {
type: String,
default: null
},
base_class: {
type: String,
default: null
},
menu_item: {
type: Object,
default: () => ({})
},
},
data() {
return {
open: false
}
},
computed: {
containerClass() {
const menuRouterName = this.menu_item.router || ""
const currentRouterName = this.$router.currentRoute._value.name || Math.random()
if (menuRouterName === currentRouterName) return `${this.base_class} ${this.base_class}--active`
return `${this.base_class}`
},
itemClass() {
if (this.open) return `${this.base_class}__sub-icon transform rotate-180`
return `${this.base_class}__sub-icon`
},
listClass() {
if (this.open) return `${this.base_class}__sub-open`
return ""
},
menu_list_with_index() {
return this.menu_item.children.map((el, index) => ({...el, index}))
}
},
methods: {
toggle() {
this.open = !this.open
}
}
}
</script>
<template>
<li>
<span
:class="containerClass"
@click="toggle"
>
<div :class="`${base_class}__icon`"> <i :icon="menu_item.icon" /> </div>
<div :class="`${base_class}__title`">
{{ menu_item.show }}
<div :class="itemClass"> <i icon="chevron-down" /> </div>
</div>
</span>
<ul :class="listClass">
<MenuItem
v-for="item in menu_item.children"
:key="JSON.stringify(item)"
:base_class="base_class"
:type="item.type"
:menu_item="item"
/>
</ul>
</li>
</template>

View File

@ -1,63 +0,0 @@
<!-- eslint-disable vue/prop-name-casing -->
<script>
import {mapGetters} from 'vuex'
import MenuItem from './MenuItem.vue'
export default {
name: 'MenuList',
components: {MenuItem},
props: {
current_menu_item: {
type: String,
default: ""
},
menu_list: {
type: Array,
default: () => []
}
},
data() {
return {
routeName: ""
}
},
computed: {
...mapGetters('', ['mobile_menu_opened', 'show_menu']),
menu_list_with_index() {
return this.menu_list.map((el, index) => ({...el, index}))
}
},
watch:{
$route (to){
this.routeName = to.name;
}
},
methods: {
rkey() {
return Math.random().toString(36).slice(4)
}
}
}
</script>
<template>
<nav
x-show="show_menu"
class="side-nav"
>
<ul>
<MenuItem
v-for="{index, ...menu_item} in menu_list_with_index"
:id="`main_menu_item_component_${index}`"
:key="rkey(index)"
base_class="side-menu"
:type="menu_item.type"
:menu_item="menu_item"
:current_menu_item="current_menu_item"
:routeName="routeName"
/>
</ul>
</nav>
</template>

View File

@ -0,0 +1,54 @@
<!-- eslint-disable vue/prop-name-casing -->
<script>
import MenuListItem from './MenuListItem.vue'
export default {
name: 'MenuList',
components: {MenuListItem},
props: {
menuListWithIndex: {
type: [{
type: String,
default: null
}],
default: () => []
},
isShowMenu: {
type: Boolean,
default: false
},
routeName: {
type: String,
required: true
}
},
data() {
return {
}
},
methods: {
randomkey() {
return Math.random().toString(36).slice(4)
}
}
}
</script>
<template>
<nav class="side-nav">
<ul>
<MenuListItem
v-for="{index, ...menuItem} in menuListWithIndex"
:id="`main_menu_item_component_${index}`"
:key="randomkey(index)"
baseClass="side-menu"
:type="menuItem.type"
:menuItem="menuItem"
:routeName="routeName"
/>
</ul>
</nav>
</template>

View File

@ -0,0 +1,31 @@
<script>
import MenuListItemImplementation from './MenuListItemImplementation.vue'
import MenuListItemGroup from "@frames/AppContainer/MenuList/MenuListItemGroup.vue";
export default {
name: 'MenuListItem',
components: {MenuListItemGroup, MenuListItemImplementation},
//eslint-disable-next-line
props: ['type', 'menuItem', 'baseClass', 'routeName'],
}
</script>
<template>
<MenuListItemImplementation
:type="type"
:menuItem="menuItem"
:baseClass="baseClass"
:routeName="routeName"
>
<MenuListItemGroup
v-if="type === 'group'"
:type="type"
:baseClass="baseClass"
:menuItem="menuItem"
:routeName="routeName"
/>
</MenuListItemImplementation>
</template>

View File

@ -0,0 +1,22 @@
<script>
import MenuListItemImplementation from './MenuListItemImplementation.vue'
export default {
name: 'MenuListItemCopy',
components: {MenuListItemImplementation},
//eslint-disable-next-line
props: ['type', 'menuItem', 'baseClass', 'routeName'],
}
</script>
<template>
<MenuListItemImplementation
:type="type"
:menuItem="menuItem"
:baseClass="baseClass"
:routeName="routeName"
/>
</template>

View File

@ -0,0 +1,85 @@
<!-- eslint-disable vue/prop-name-casing -->
<script>
import MenuItem from './MenuListItemCopy.vue'
export default {
name: 'MenuItemGroup',
components: {
MenuItem
},
props: {
type: {
type: String,
default: null
},
baseClass: {
type: String,
default: null
},
menuItem: {
type: {
show: String,
children: Array,
router: String
},
default: () => ({})
},
routeName: {
type: String,
default: ""
}
},
data() {
return {
open: false
}
},
computed: {
containerClass() {
const routeName = this.routeName
const menuRouterName = this.menuItem.router || ""
if (menuRouterName === routeName) return `${this.baseClass} ${this.baseClass}--active`
return `${this.baseClass}`
},
itemClass() {
if (this.open) return `${this.baseClass}__sub-icon transform rotate-180`
return `${this.baseClass}__sub-icon`
},
listClass() {
if (this.open) return `${this.baseClass}__sub-open`
return ""
},
},
methods: {
toggle() {
this.open = !this.open
}
}
}
</script>
<template>
<li>
<span
:class="containerClass"
@click="toggle"
>
<div :class="`${baseClass}__icon`"> <i :icon="menuItem.icon" /> </div>
<div :class="`${baseClass}__title`">
{{ menuItem.show }}
<div :class="itemClass"> <i icon="chevron-down" /> </div>
</div>
</span>
<ul :class="listClass">
<MenuItem
v-for="item in menuItem.children"
:key="JSON.stringify(item)"
:baseClass="baseClass"
:type="item.type"
:menuItem="item"
/>
</ul>
</li>
</template>

View File

@ -0,0 +1,89 @@
<script>
import { cond, equals, T } from 'ramda'
import { createIcons, icons } from "lucide";
export default {
name: 'MenuItem',
props: {
type: {
type: String,
default: null
},
menuItem: {
type: {
line: String,
icon: String,
},
default: () => ({
link: "/"
})
},
baseClass: {
type: String,
default: ""
},
routeName: {
type: String,
default: ""
}
},
data() {
return {}
},
computed: {
linkClass() {
const menuRouterName = this.menuItem.router || ""
if (menuRouterName === this.routeName)
return `${this.baseClass} ${this.baseClass}--active`
return this.baseClass
},
_type() {
return cond([
[equals("simple_link"), (x) => x],
[equals("line"), (x) => x],
[equals("group"), (x) => x],
[T, () => "other"],
])(this.type)
}
},
mounted() {
this.icons()
},
updated() {
this.icons()
},
methods: {
icons() {
createIcons({ icons, nameAttr: "icon" })
}
}
}
</script>
<template>
<li v-if="_type === 'simple_link'">
<router-link
phx-hook="MenuLink"
:class="linkClass"
:to="menuItem.link"
>
<div :class="`${baseClass}__icon`">
<i :icon="menuItem?.icon" />
</div>
<div :class="`${baseClass}__title`">
{{ menuItem.show }}
</div>
</router-link>
</li>
<li v-if="_type === 'line'">
<hr class="m-4">
</li>
<slot />
<div v-if="_type === 'other'">
""
</div>
</template>

View File

@ -1,63 +0,0 @@
<script>
import MenuItem from './MenuItem.vue'
export default {
name: 'MobileMenu',
components: {
MenuItem
},
props: {
// eslint-disable-next-line vue/prop-name-casing
current_menu_item: {
type: String,
default: ""
},
// eslint-disable-next-line vue/prop-name-casing
menu_list: {
type: Array,
default: () => []
}
},
data() {
},
computed: {
menu_list_with_index() {
return this.menu_list.map((el, index) => ({...el, index}))
}
},
methods: {
rkey() {
return Math.random().toString(36).slice(4)
}
}
}
</script>
<template>
<div x-bind:class="mobile_menu_opened ? 'mobile-menu--active mobile-menu md:hidden' : 'mobile-menu md:hidden'">
<div class="scrollable">
<span
class="mobile-menu-toggler"
@click="mobile_menu_opened = !mobile_menu_opened"
>
<i
icon="x-circle"
class="w-8 h-8 text-white transform -rotate-90"
/>
</span>
<ul class="scrollable__content py-2">
<MenuItem
v-for="{index, ...menu_item} in menu_list_with_index"
:id="`main_menu_item_component_${index}`"
:key="rkey(index)"
base_class="menu"
:type="menu_item.type"
:menu_item="menu_item"
:current_menu_item="current_menu_item"
/>
</ul>
</div>
</div>
</template>

View File

@ -0,0 +1,14 @@
<script>
export default {
name: "PacksContainer",
}
</script>
<template>
<div class="grid grid-cols-12 gap-6 col-span-12 h-full">
<slot />
</div>
</template>

View File

@ -0,0 +1,14 @@
<script>
export default {
name: "PacksContainerBody"
}
</script>
<template>
<div class="">
ComponentTemplate
</div>
</template>

View File

@ -0,0 +1,18 @@
<script>
export default {
name: "PacksContainerControl",
}
</script>
<template>
<form
phx-submit="fetch_pack"
class="rounded-md bg-light px-4 pt-4 pb-6 gap-2 shadow lg:col-span-4 xl:col-span-3 2xl:col-span-2 col-span-12"
autocomplete="off"
>
<slot />
</form>
</template>

View File

@ -1,3 +1,64 @@
<script>
import ButtonModal from '@molecules/ButtonModal/ButtonModal.vue'
import Datepicker from "@molecules/VDatepicker/VDatepicker.vue"
import {mapGetters, mapMutations, mapActions} from 'vuex'
import Tabulator from "@molecules/VTabulator/VTabulator.vue"
import Spinner from "@molecules/VSpinner/VSpinner.vue"
import MachinesModal from "@molecules/MachinesModal/MachinesModal.vue"
export default {
name: 'LastPacks',
components: {
Datepicker,
ButtonModal,
Tabulator,
Spinner,
MachinesModal
},
data() {
return {
packNum: null,
}
},
computed: {
...mapGetters('last_packs', ['dtStart', 'dtFinish', 'imei', 'pageState', 'packsData']),
tabulatorOtps() {
return {
dataSource: this.packsData,
columns: [
{
title: "Нормер пакета",
field: "pack_number",
width: 150
},
{
title: "Количество записей",
field: "count",
width: 150
},
{
title: "Последняя дата пакета",
field: "pack_dt",
width: 150,
render: "{{ dt_format (dt_shift pack_dt 3 'hour') }}"
}
],
height: "550px"
}
}
},
methods: {
...mapMutations('last_packs', [
"setDtStart",
"setDtFinish",
"setImei"
]),
...mapActions('last_packs', ['uploadData'])
}
}
</script>
<template> <template>
<div class="grid grid-cols-12 gap-6 col-span-12 h-full"> <div class="grid grid-cols-12 gap-6 col-span-12 h-full">
<form <form
@ -99,64 +160,3 @@
</div> </div>
</div> </div>
</template> </template>
<script>
import ButtonModal from '@molecules/ButtonModal/ButtonModal.vue'
import Datepicker from "@molecules/VDatepicker/VDatepicker.vue"
import {mapGetters, mapMutations, mapActions} from 'vuex'
import Tabulator from "@molecules/VTabulator/VTabulator.vue"
import Spinner from "@molecules/VSpinner/VSpinner.vue"
import MachinesModal from "@molecules/MachinesModal/MachinesModal.vue"
export default {
name: 'LastPacks',
components: {
Datepicker,
ButtonModal,
Tabulator,
Spinner,
MachinesModal
},
data() {
return {
packNum: null,
}
},
computed: {
...mapGetters('last_packs', ['dtStart', 'dtFinish', 'imei', 'pageState', 'packsData']),
tabulatorOtps() {
return {
dataSource: this.packsData,
columns: [
{
title: "Нормер пакета",
field: "pack_number",
width: 150
},
{
title: "Количество записей",
field: "count",
width: 150
},
{
title: "Последняя дата пакета",
field: "pack_dt",
width: 150,
render: "{{ dt_format (dt_shift pack_dt 3 'hour') }}"
}
],
height: "550px"
}
}
},
methods: {
...mapMutations('last_packs', [
"setDtStart",
"setDtFinish",
"setImei"
]),
...mapActions('last_packs', ['uploadData'])
}
}
</script>

View File

@ -0,0 +1,43 @@
class ServiceOfLayout {
constructor(store) {
this.store = store
}
getHeight() {
return this.store.getters['layout/height']
}
getWidth() {
return this.store.getters['layout/width']
}
getIsOpenMenu() {
return this.store.getters['layout/isOpenMenu']
}
getIsShowMenu() {
return this.store.getters['layout/isShowMenu']
}
getIsEnabledMenu() {
return this.store.getters['layout/isEnabledMenu']
}
setIsShowMenu(upd) {
this.store.dispatch('layout/setIsShowMenu', upd)
}
setIsMobileMenuOpened(upd) {
this.store.dispatch('layout/setIsMobileMenuOpened', upd)
}
setIsOpenMenu(upd) {
this.store.dispatch('layout/setIsOpenMenu', upd)
}
setIsEnabledMenu(upd) {
this.store.dispatch('layout/setIsEnabledMenu', upd)
}
toggleMenu() {
this.store.dispatch('layout/toggleMenu')
}
}
export default ServiceOfLayout

View File

@ -6,7 +6,7 @@ import axios from 'axios';
import {orisMenu} from './menuList' import {orisMenu} from './menuList'
const initState = { const initState = {
current_user: null, currentUser: null,
errorMsg: null, errorMsg: null,
token: null, token: null,
inited: false, inited: false,
@ -17,7 +17,7 @@ const state = {
...initState ...initState
}; };
const current_user = (token) => ({ const setCurrentUser = (token) => ({
position: "", position: "",
first_name: "Сергей", first_name: "Сергей",
last_name: "Шлыков", last_name: "Шлыков",
@ -31,17 +31,17 @@ const getters = {
login: (state) => state.login, login: (state) => state.login,
password: (state) => state.password, password: (state) => state.password,
my_comp: (state) => state.my_comp, my_comp: (state) => state.my_comp,
current_user: (state) => state.current_user, currentUser: (state) => state.currentUser,
menuList: () => orisMenu, menuList: () => orisMenu,
}; };
const mutations = { const mutations = {
initAuth: (state, token) => { initAuth: (state, token) => {
state.current_user = current_user(token) state.currentUser = setCurrentUser(token)
state.token = token; state.token = token;
state.inited = true state.inited = true
}, },
set_my_comp: (state, upd) => state.my_comp, set_my_comp: (state) => state.my_comp,
}; };

View File

@ -1,12 +1,11 @@
const orisMenu = [ const orisMenu = [
{ {
type: "simple_link", type: "simple_link",
icon: "home", icon: "home",
show: "Главная", show: "Главная",
link: "/", link: "/",
router: "main" router: "machines"
}, },
{ {
type: "simple_link", type: "simple_link",

View File

@ -1,58 +1,94 @@
import {initScreenListener, disableScreenListener} from "./stateHelpers.js";
const initState = {
height: 0,
width: 0,
isOpenMenu: false,
isOpenedMobileMenu: false,
isEnabledMenu: true,
isShowMenu: true,
initedScreenListener: false,
};
const state = { const state = {
height: 0, ...initState
width: 0,
inited: false,
isOpenMenu: false,
mobile_menu_opened: false,
show_menu: true,
is_enabled_menu: true
}; };
const getters = { const getters = {
height: (state) => state.height, height: (state) => state.height,
width: (state) => state.width, width: (state) => state.width,
isOpenMenu: (state) => state.isOpenMenu, isOpenMenu: (state) => state.isOpenMenu,
menuWidth: (state) => null, isShowMenu: (state) => state.isShowMenu,
show_menu: (state) => state.show_menu, isOpenedMobileMenu: (state) => state.isOpenedMobileMenu,
is_enabled_menu: (state) => state.is_enabled_menu, isEnabledMenu: (state) => state.isEnabledMenu,
initedScreenListener: (state) => state.initedScreenListener,
}; };
const mutations = { const mutations = {
enableScreenListener: (state) => { enableScreenListener: (state) => {
state.height = window.innerHeight const inited = state.initedScreenListener
state.width = window.innerWidth if (!inited) {
const acc = !!state.inited initScreenListener(state)
if (!acc) { state.initedScreenListener = true
window.addEventListener("resize", (e) => {
state.height= e.target.innerHeight
state.width = e.target.innerWidth
});
state.inited = true
} }
}, },
toggle_menu: (state) => { disableScreenListener: (state) => {
state.show_menu = !state.show_menu disableScreenListener(state)
}, },
set_mobile_menu_opened: (state, upd) => { toggleMenu: (state) => {
state.mobile_menu_opened = upd state.isShowMenu = !state.isShowMenu
}, },
set_show_menu: (state, upd) => { saveIsMobileMenuOpened: (state, upd) => {
state.show_menu = upd state.isOpenedMobileMenu = upd
},
saveIsShowMenu: (state, upd) => {
state.isShowMenu = upd
},
resetStore: (state) => {
for (let key in state) {
state[key] = initState[key]
}
},
saveIsEnabledMenu: (state, upd) => {
state.isEnabledMenu = upd
},
saveIsOpenMenu: (state, upd) => {
state.isOpenMenu = upd
}, },
}; };
const actions = { const actions = {
initScreenSizeRecalc: ({commit}) => { initScreenSizeListener: ({commit}) => {
commit("enableScreenListener") commit("enableScreenListener")
}, },
disableScreenListener: ({commit}) => {
commit("disableScreenListener")
},
resetStore: ({commit}) => {
commit("resetStore")
},
toggleMenu: ({commit}) => {
commit("toggleMenu")
},
setIsShowMenu: ({commit}, upd) => {
commit("saveIsShowMenu", upd)
},
setIsMobileMenuOpened: ({commit}, upd) => {
commit("saveIsMobileMenuOpened", upd)
},
setIsEnabledMenu: ({commit}, upd) => {
commit("saveIsEnabledMenu", upd)
},
setIsOpenMenu: ({commit}, upd) => {
commit("saveIsOpenMenu", upd)
},
}; };
export const store = { export const store = {
namespaced: true, namespaced: true,
state, state,
getters, getters,
mutations, mutations,
actions, actions,
}; };

View File

@ -1,126 +0,0 @@
const orisMenu = [
{
type: "simple_link",
icon: "home",
show: "Главная",
link: "/",
router: "main"
},
{
type: "simple_link",
icon: "book-marked",
show: "Последние пакеты",
link: "/html/last_packs",
router: "last_packs"
},
{
type: "simple_link",
icon: "box",
show: "Коммуникационный",
link: "/html/controll_com_service",
router: "comm"
},
{
type: "simple_link",
icon: "book-key",
show: "Последние пакеты(по номеру)",
link: "/html/last_packs_by_pack",
router: "last_pack_number"
},
{
type: "simple_link",
icon: "beaker",
show: "Топливо",
link: "/html/live_fuel",
router: "fuel"
},
{type: "simple_link", icon: "timer", show: "Крон", link: "/html/cron", router: "cron"},
{
type: "group",
show: "Справочники",
icon: "book",
children: [
{type: "simple_link", icon: "book-open", show: "ICCID", link: "/html/fetch_iccid"},
{
type: "simple_link",
icon: "book-open",
show: "Устройства",
link: "/html/fetch_askr_devices"
}
]
},
{
type: "group",
show: "Пакеты",
icon: "cast",
children:
[
{
type: "simple_link",
icon: "curly-braces",
show: "Свободный поиск",
link: "/html/free_packs"
}
]
},
{type: "line"},
{
type: "group",
show: "Логи",
icon: "fingerprint",
children: [
{
type: "simple_link",
icon: "code",
show: "Файлы логов",
link: "/html/file_viewer/logs"
},
{
type: "simple_link",
icon: "code",
show: "Файлы машин",
link: "/html/file_viewer/machine_data"
}
]
},
{type: "line"},
{
type: "group",
show: "Работоспособность сервсисов",
icon: "cloud-cog",
children: [
{
type: "simple_link",
icon: "cpu",
show: "ДИАП",
link: "/admin_panel/services/diap"
},
{type: "simple_link", icon: "table", show: "Сервисы", link: "/html/communications"},
]
},
{
type: "group",
show: "Админка",
icon: "hand-metal",
children: [
{
type: "simple_link",
icon: "haze",
show: "Сервис управления",
link: "/admin_panel/auth_service"
},
{
type: "simple_link",
icon: "line-chart",
show: "Анализ топлива",
link: "/admin_panel/fuel_analyzer"
},
{type: "simple_link", icon: "newspaper", show: "Обновления", link: "/html/updates"},
{type: "simple_link", icon: "boxes", show: "Пакеты", link: "/admin_panel/packs"}
]
},
{type: "line"},
{type: "simple_link", icon: "newspaper", show: "Обновления", link: "/html/updates", router: "news"},
]
export {orisMenu}

View File

@ -0,0 +1,19 @@
const initScreenListener = (state) => {
state.height = window.innerHeight
state.width = window.innerWidth
window.addEventListener("resize", (e) => {
state.height= e.target.innerHeight
state.width = e.target.innerWidth
});
return "ok"
}
const disableScreenListener = (state) => {
window.removeEventListener("resize", () => {
state.height = null
state.width = null
});
return "ok"
}
export { initScreenListener, disableScreenListener }

View File

@ -7,7 +7,7 @@
&.mobile-menu--active { &.mobile-menu--active {
&:before { &:before {
content: ""; content: "";
@apply visible opacity-100; @apply visible opacity-100 h-[110vh];
} }
.scrollable { .scrollable {
@apply ml-0 overflow-y-auto; @apply ml-0 overflow-y-auto;

View File

@ -1,10 +1,10 @@
import {test, describe, expect} from 'vitest' import {test, describe, expect} from 'vitest'
import { mount} from '@vue/test-utils' import { mount} from '@vue/test-utils'
import Button from '@atoms/VButton.vue'; import VButton from '@atoms/VButton.vue';
describe('Accordion', () => { describe('VButton', () => {
test('Accordion mounted', () => { test('VButton mounted', () => {
const wrapper = mount(Button) const wrapper = mount(VButton)
expect(wrapper.exists()).toBe(true) expect(wrapper.exists()).toBe(true)
}) })
}) })

View File

@ -0,0 +1,27 @@
import {test, describe, expect, } from 'vitest'
import { shallowMount} from '@vue/test-utils'
import AppContainer from '@frames/AppContainer/AppContainer.vue';
import {createStore} from "vuex";
import { store as layout } from '@/store/modules/layout';
import { store as auth } from '@/store/modules/auth';
describe('AppContainer', () => {
const store = createStore({
modules: {
layout,
auth
},
})
test('AppContainer mounted', () => {
const wrapper = shallowMount(AppContainer,
{
global: {
mocks: {
$store: store,
},
}}
)
expect(wrapper.exists()).toBe(true)
})
})

View File

@ -0,0 +1,10 @@
import {test, describe, expect, } from 'vitest'
import { shallowMount} from '@vue/test-utils'
import AppContainerBreadcrumbs from '@frames/AppContainer/AppContainerBreadcrumbs.vue';
describe('AppContainerBreadcrumbs', () => {
test('AppContainerBreadcrumbs mounted', () => {
const wrapper = shallowMount(AppContainerBreadcrumbs)
expect(wrapper.exists()).toBe(true)
})
})

View File

@ -0,0 +1,10 @@
import {test, describe, expect, } from 'vitest'
import { shallowMount} from '@vue/test-utils'
import AppContainerHeader from '@frames/AppContainer/AppContainerHeader.vue';
describe('AppContainerHeader', () => {
test('AppContainerHeader mounted', () => {
const wrapper = shallowMount(AppContainerHeader)
expect(wrapper.exists()).toBe(true)
})
})

View File

@ -0,0 +1,16 @@
import {test, describe, expect, } from 'vitest'
import { shallowMount} from '@vue/test-utils'
import AppContainerLeftPanel from '@frames/AppContainer/AppContainerLeftPanel.vue';
import Router from "@router"
describe('AppContainerLeftPanel', () => {
test('AppContainerLeftPanel mounted', () => {
const wrapper = shallowMount(AppContainerLeftPanel,
{
global: {
plugins: [Router]
}
})
expect(wrapper.exists()).toBe(true)
})
})

View File

@ -0,0 +1,15 @@
import {test, describe, expect, } from 'vitest'
import { shallowMount} from '@vue/test-utils'
import AppContainerMobileMenu from '@frames/AppContainer/AppContainerMobileMenu.vue';
describe('AppContainerMobileMenu', () => {
test('AppContainerMobileMenu mounted', () => {
const wrapper = shallowMount(AppContainerMobileMenu, {
props: {
isOpenedMobileMenu: false,
setIsMobileMenuOpened: () => {},
}
})
expect(wrapper.exists()).toBe(true)
})
})

View File

@ -0,0 +1,20 @@
import {test, describe, expect, } from 'vitest'
import { shallowMount} from '@vue/test-utils'
import AppContainerRightPanel from '@frames/AppContainer/AppContainerRightPanel.vue';
import Router from "@router"
describe('AppContainerRightPanel', () => {
test('AppContainerRightPanel mounted', () => {
const wrapper = shallowMount(AppContainerRightPanel, {
props: {
currentUser: {
id: 1,
}
},
global: {
plugins: [Router]
}
})
expect(wrapper.exists()).toBe(true)
})
})

View File

@ -0,0 +1,15 @@
import {test, describe, expect, } from 'vitest'
import { shallowMount} from '@vue/test-utils'
import MenuList from '@frames/AppContainer/MenuList/MenuList.vue';
describe('MenuList', () => {
test('MenuList mounted', () => {
const wrapper = shallowMount(MenuList, {
props: {
routeName: ""
}
})
expect(wrapper.exists()).toBe(true)
})
})

View File

@ -0,0 +1,11 @@
import {test, describe, expect, } from 'vitest'
import { shallowMount} from '@vue/test-utils'
import MenuListItem from '@frames/AppContainer/MenuList/MenuListItem.vue';
describe('MenuListItem', () => {
test('MenuListItem mounted', () => {
const wrapper = shallowMount(MenuListItem)
expect(wrapper.exists()).toBe(true)
})
})

View File

@ -0,0 +1,10 @@
import {test, describe, expect, } from 'vitest'
import { shallowMount} from '@vue/test-utils'
import MenuListItemCopy from '@frames/AppContainer/MenuList/MenuListItemCopy.vue';
describe('MenuListItemCopy', () => {
test('MenuListItemCopy mounted', () => {
const wrapper = shallowMount(MenuListItemCopy)
expect(wrapper.exists()).toBe(true)
})
})

View File

@ -0,0 +1,10 @@
import {test, describe, expect, } from 'vitest'
import { shallowMount} from '@vue/test-utils'
import MenuListItemGroup from '@frames/AppContainer/MenuList/MenuListItemGroup.vue';
describe('MenuListItemGroup', () => {
test('MenuListItemGroup mounted', () => {
const wrapper = shallowMount(MenuListItemGroup)
expect(wrapper.exists()).toBe(true)
})
})

View File

@ -0,0 +1,17 @@
import {test, describe, expect, } from 'vitest'
import { shallowMount} from '@vue/test-utils'
import MenuListItemImplementation from '@frames/AppContainer/MenuList/MenuListItemImplementation.vue';
import Router from "@router"
describe('MenuListItemImplementation', () => {
test('MenuListItemImplementation mounted', () => {
const wrapper = shallowMount(MenuListItemImplementation,
{
global: {
plugins: [Router]
}
})
expect(wrapper.exists()).toBe(true)
})
})

View File

@ -0,0 +1,10 @@
import {test, describe, expect} from 'vitest'
import { mount} from '@vue/test-utils'
import PacksContainer from '@frames/PacksContainer/PacksContainer.vue';
describe('PacksContainer', () => {
test('PacksContainer mounted', () => {
const wrapper = mount(PacksContainer)
expect(wrapper.exists()).toBe(true)
})
})

View File

@ -0,0 +1,10 @@
import {test, describe, expect} from 'vitest'
import { mount} from '@vue/test-utils'
import PacksContainerBody from '@frames/PacksContainer/PacksContainerBody.vue';
describe('PacksContainerBody', () => {
test('PacksContainerBody mounted', () => {
const wrapper = mount(PacksContainerBody)
expect(wrapper.exists()).toBe(true)
})
})

View File

@ -0,0 +1,10 @@
import {test, describe, expect} from 'vitest'
import { mount} from '@vue/test-utils'
import PacksContainerControl from '@frames/PacksContainer//PacksContainerControl.vue';
describe('PacksContainerControl', () => {
test('PacksContainerControl mounted', () => {
const wrapper = mount(PacksContainerControl)
expect(wrapper.exists()).toBe(true)
})
})

View File

@ -0,0 +1,51 @@
import {expect, describe, test, beforeEach} from 'vitest'
import ServiceOfLayout from "@services/ServiceOfLayout.js"
import { createStore } from "vuex"
import { store as layout } from '@/store/modules/layout';
describe('test ServiceOfLayout', () => {
const store = createStore({
modules: {
layout
}
})
beforeEach(() => {
store.dispatch('layout/resetStore')
})
const serviceOfLayout = new ServiceOfLayout(store)
test('test ServiceOfLayout exist', async () => {
expect(serviceOfLayout).toBeTruthy()
expect(serviceOfLayout.getHeight()).toBe(0)
expect(serviceOfLayout.getWidth()).toBe(0)
expect(serviceOfLayout.getIsOpenMenu()).toBe(false)
expect(serviceOfLayout.getIsEnabledMenu()).toBe(true)
expect(serviceOfLayout.getIsShowMenu()).toBe(true)
})
test('test toggleMenu', async () => {
serviceOfLayout.toggleMenu()
const result = store.getters['layout/isShowMenu']
expect(result).toBe(false)
})
test('setIsShowMenu', async () => {
serviceOfLayout.setIsShowMenu(false)
const result = serviceOfLayout.getIsShowMenu()
expect(result).toBe(false)
})
test('setIsOpenMenu', async () => {
serviceOfLayout.setIsOpenMenu(true)
const result = serviceOfLayout.getIsOpenMenu()
expect(result).toBe(true)
})
test('setIsEnabledMenu', async () => {
serviceOfLayout.setIsEnabledMenu(false)
const result = serviceOfLayout.getIsEnabledMenu()
expect(result).toBe(false)
})
})

View File

@ -0,0 +1,53 @@
import {expect, describe, test, beforeEach} from 'vitest'
import { createStore } from "vuex"
import { store as layout } from '@/store/modules/layout';
describe('test of layout store', () => {
const store = createStore({
modules: {
layout
}
})
beforeEach(() => {
store.dispatch('layout/resetStore')
})
test('test layout store exist', async () => {
expect(store).toBeTruthy()
expect(store.getters['layout/isOpenedMobileMenu']).toBe(false)
expect(store.getters['layout/isEnabledMenu']).toBe(true)
})
test('test toggleMenu', () => {
store.dispatch('layout/toggleMenu')
const result = store.getters['layout/isShowMenu']
expect(result).toBe(false)
})
test('test setIsShowMenu', () => {
store.dispatch('layout/setIsShowMenu', false)
const result = store.getters['layout/isShowMenu']
expect(result).toBe(false)
})
test('test setIsMobileMenuOpened', () => {
store.dispatch('layout/setIsMobileMenuOpened', true)
const result = store.getters['layout/isOpenedMobileMenu']
expect(result).toBe(true)
})
test('test resetStore', () => {
store.dispatch('layout/resetStore')
const result = store.getters['layout/isShowMenu']
expect(result).toBe(true)
})
test('test initScreenSizeListener', () => {
store.dispatch('layout/initScreenSizeListener')
const result = store.getters['layout/initedScreenListener']
expect(result).toBe(true)
})
})