adata-ui 2.1.40-beta.5 → 2.1.40-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/elements/a-select-row/ASelectRowV2.vue +5 -4
- package/components/elements/select/ASelectV2.vue +17 -9
- package/components/modals/id/IdConfirmAccountOtpModal.vue +4 -9
- package/components/modals/id/IdLoginModal.vue +3 -8
- package/components/modals/id/IdModals.vue +23 -10
- package/components/modals/id/IdTwoFactorModal.vue +3 -8
- package/components/navigation/header/HeaderLink.vue +15 -21
- package/components/navigation/header/NavList.vue +8 -32
- package/components/navigation/header/ProductMenu.vue +52 -50
- package/composables/useAccessTokenCookie.ts +25 -0
- package/composables/useChipOverflow.ts +17 -7
- package/composables/useHeaderNavigationLinks.ts +53 -23
- package/icons/arrow/arrow-right.vue +14 -0
- package/icons/briefcase.vue +14 -0
- package/icons/car-side.vue +16 -0
- package/icons/cart.vue +15 -0
- package/icons/download-rounded.vue +15 -0
- package/icons/shield-verified.vue +14 -0
- package/lang/en.ts +34 -4
- package/lang/kk.ts +34 -4
- package/lang/ru.ts +36 -6
- package/package.json +1 -1
- package/shared/constans/pages.ts +8 -2
|
@@ -42,6 +42,7 @@ const { visibleCount, hiddenCount } = useChipOverflow({
|
|
|
42
42
|
container: chipsRow,
|
|
43
43
|
measure: measureRow,
|
|
44
44
|
count: itemCount,
|
|
45
|
+
contentKey: computed(() => props.selectedItems?.map(item => item.name).join(' ') ?? ''),
|
|
45
46
|
gap: 6,
|
|
46
47
|
})
|
|
47
48
|
|
|
@@ -101,7 +102,7 @@ defineExpose({ onClear })
|
|
|
101
102
|
<span
|
|
102
103
|
v-for="item in visibleItems"
|
|
103
104
|
:key="item.id"
|
|
104
|
-
class="select-row-v2__chip inline-flex min-w-0
|
|
105
|
+
class="select-row-v2__chip inline-flex min-w-0 items-center gap-1 rounded-md border border-gray-200 bg-gray-50 px-2 py-0.5 text-xs dark:border-gray-700 dark:bg-white/[0.06]"
|
|
105
106
|
@click.stop="deletable ? deleteItem(item) : (isOpen = true)"
|
|
106
107
|
>
|
|
107
108
|
<span class="truncate">{{ item.name }}</span>
|
|
@@ -123,14 +124,14 @@ defineExpose({ onClear })
|
|
|
123
124
|
<span
|
|
124
125
|
ref="measureRow"
|
|
125
126
|
aria-hidden="true"
|
|
126
|
-
class="pointer-events-none invisible absolute left-0 top-0 flex h-0 items-center gap-1.5"
|
|
127
|
+
class="pointer-events-none invisible absolute left-0 top-0 flex h-0 w-max items-center gap-1.5"
|
|
127
128
|
>
|
|
128
129
|
<span
|
|
129
130
|
v-for="item in selectedItems"
|
|
130
131
|
:key="`measure-${item.id}`"
|
|
131
|
-
class="inline-flex
|
|
132
|
+
class="inline-flex items-center gap-1 whitespace-nowrap rounded-md border border-gray-200 bg-gray-50 px-2 py-0.5 text-xs"
|
|
132
133
|
>
|
|
133
|
-
<span
|
|
134
|
+
<span>{{ item.name }}</span>
|
|
134
135
|
<span
|
|
135
136
|
v-if="deletable"
|
|
136
137
|
class="flex shrink-0 items-center justify-center rounded-full p-0.5"
|
|
@@ -182,9 +182,10 @@ const valueToShow = computed<T | T[] | null>(() => {
|
|
|
182
182
|
if (!Array.isArray(modelValue.value) || modelValue.value.length === 0) return null
|
|
183
183
|
if (props.getOnlyKey) {
|
|
184
184
|
const keys = modelValue.value as any[]
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
185
|
+
// map over model keys (not options) so chips keep the selection order
|
|
186
|
+
const found = keys
|
|
187
|
+
.map(k => props.options.find(opt => isEqual(k, opt[props.keyToSelect as keyof T])))
|
|
188
|
+
.filter((opt): opt is T => opt != null)
|
|
188
189
|
return found.length ? found : null
|
|
189
190
|
}
|
|
190
191
|
return modelValue.value as T[]
|
|
@@ -249,8 +250,11 @@ function onClear() {
|
|
|
249
250
|
emits('onClear')
|
|
250
251
|
}
|
|
251
252
|
|
|
252
|
-
function onClearFromMulti(
|
|
253
|
+
function onClearFromMulti(item: T) {
|
|
253
254
|
if (!Array.isArray(modelValue.value)) return
|
|
255
|
+
const key = selectedKey(item)
|
|
256
|
+
const index = modelValue.value.findIndex(el => isEqual(el, key))
|
|
257
|
+
if (index === -1) return
|
|
254
258
|
const next = [...modelValue.value]
|
|
255
259
|
next.splice(index, 1)
|
|
256
260
|
modelValue.value = next
|
|
@@ -267,6 +271,10 @@ const { visibleCount: visibleChipCount, hiddenCount: hiddenChipCount } = useChip
|
|
|
267
271
|
container: valueColumn,
|
|
268
272
|
measure: measureRow,
|
|
269
273
|
count: selectedCount,
|
|
274
|
+
contentKey: computed(() => {
|
|
275
|
+
if (!Array.isArray(valueToShow.value)) return ''
|
|
276
|
+
return (valueToShow.value as any[]).map(item => item?.[props.keyToShow]).join(' ')
|
|
277
|
+
}),
|
|
270
278
|
gap: 6,
|
|
271
279
|
})
|
|
272
280
|
|
|
@@ -332,8 +340,8 @@ const isDefaultSelection = computed(() => {
|
|
|
332
340
|
<span
|
|
333
341
|
v-for="(item, index) in (valueToShow as any[]).slice(0, visibleChipCount)"
|
|
334
342
|
:key="index"
|
|
335
|
-
class="select-v2__chip inline-flex min-w-0
|
|
336
|
-
@click.stop="canChipRemove ? onClearFromMulti(
|
|
343
|
+
class="select-v2__chip inline-flex min-w-0 items-center gap-1 rounded-md border border-gray-200 bg-gray-50 px-2 py-0.5 text-xs dark:border-gray-700 dark:bg-white/[0.06]"
|
|
344
|
+
@click.stop="canChipRemove ? onClearFromMulti(item) : (isOpen = true)"
|
|
337
345
|
>
|
|
338
346
|
<span class="truncate">{{ item[keyToShow] }}</span>
|
|
339
347
|
<button
|
|
@@ -354,14 +362,14 @@ const isDefaultSelection = computed(() => {
|
|
|
354
362
|
<span
|
|
355
363
|
ref="measureRow"
|
|
356
364
|
aria-hidden="true"
|
|
357
|
-
class="pointer-events-none invisible absolute left-0 top-0 flex h-0 items-center gap-1.5"
|
|
365
|
+
class="pointer-events-none invisible absolute left-0 top-0 flex h-0 w-max items-center gap-1.5"
|
|
358
366
|
>
|
|
359
367
|
<span
|
|
360
368
|
v-for="(item, index) in (valueToShow as any[])"
|
|
361
369
|
:key="`measure-${index}`"
|
|
362
|
-
class="inline-flex
|
|
370
|
+
class="inline-flex items-center gap-1 whitespace-nowrap rounded-md border border-gray-200 bg-gray-50 px-2 py-0.5 text-xs"
|
|
363
371
|
>
|
|
364
|
-
<span
|
|
372
|
+
<span>{{ item[keyToShow] }}</span>
|
|
365
373
|
<span
|
|
366
374
|
v-if="canChipRemove"
|
|
367
375
|
class="flex shrink-0 items-center justify-center rounded-full p-0.5"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
|
|
3
2
|
import IdOtpInput from '#adata-ui/components/modals/id/IdOtpInput.vue'
|
|
3
|
+
import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
|
|
4
|
+
import { writeAccessTokenCookie } from '#adata-ui/composables/useAccessTokenCookie'
|
|
4
5
|
|
|
5
6
|
const { $toast } = useNuxtApp()
|
|
6
7
|
const { t, locale } = useI18n()
|
|
@@ -40,17 +41,11 @@ async function loginUser() {
|
|
|
40
41
|
},
|
|
41
42
|
})
|
|
42
43
|
const { data: cookiesData } = await response.json()
|
|
43
|
-
if (cookiesData) {
|
|
44
|
+
if (cookiesData?.access_token) {
|
|
44
45
|
const { access_token, expire_in } = cookiesData
|
|
45
|
-
const hostname = location.hostname.split('.').reverse()
|
|
46
46
|
useCookie('autoLogout').value = true
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
maxAge: expire_in,
|
|
50
|
-
domain: `.${hostname[1]}.${hostname[0]}`,
|
|
51
|
-
path: '/',
|
|
52
|
-
secure: true,
|
|
53
|
-
}).value = access_token
|
|
48
|
+
await writeAccessTokenCookie(access_token, expire_in)
|
|
54
49
|
}
|
|
55
50
|
}
|
|
56
51
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
|
|
3
|
+
import { writeAccessTokenCookie } from '#adata-ui/composables/useAccessTokenCookie'
|
|
3
4
|
import { navigateToLocalizedPage } from '#adata-ui/utils/localizedNavigation'
|
|
4
5
|
import * as z from 'zod'
|
|
5
6
|
import { useUrls } from '#adata-ui/composables/useUrls'
|
|
@@ -127,17 +128,11 @@ async function submit() {
|
|
|
127
128
|
},
|
|
128
129
|
})
|
|
129
130
|
const { data: cookiesData } = await response.json()
|
|
130
|
-
if (cookiesData) {
|
|
131
|
+
if (cookiesData?.access_token) {
|
|
131
132
|
const { access_token, expire_in } = cookiesData
|
|
132
|
-
const hostname = location.hostname.split('.').reverse()
|
|
133
133
|
useCookie('autoLogout').value = true
|
|
134
134
|
|
|
135
|
-
|
|
136
|
-
maxAge: expire_in,
|
|
137
|
-
domain: COOKIE_DOMAIN,
|
|
138
|
-
path: '/',
|
|
139
|
-
secure: true,
|
|
140
|
-
}).value = access_token
|
|
135
|
+
await writeAccessTokenCookie(access_token, expire_in)
|
|
141
136
|
}
|
|
142
137
|
$toast.success(t('reuse.successfully'))
|
|
143
138
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import IdAutoLogoutModal from '#adata-ui/components/modals/id/IdAutoLogoutModal.vue'
|
|
3
3
|
import IdConfirmAccountOtpModal from '#adata-ui/components/modals/id/IdConfirmAccountOtpModal.vue'
|
|
4
4
|
import IdConfirmSuccessfulModal from '#adata-ui/components/modals/id/IdConfirmSuccessfulModal.vue'
|
|
5
5
|
import IdLoginModal from '#adata-ui/components/modals/id/IdLoginModal.vue'
|
|
@@ -9,7 +9,8 @@ import IdRecoveryModal from '#adata-ui/components/modals/id/IdRecoveryModal.vue'
|
|
|
9
9
|
import IdRegistrationModal from '#adata-ui/components/modals/id/IdRegistrationModal.vue'
|
|
10
10
|
import IdResetPasswordOtpModal from '#adata-ui/components/modals/id/IdResetPasswordOtpModal.vue'
|
|
11
11
|
import IdTwoFactorModal from '#adata-ui/components/modals/id/IdTwoFactorModal.vue'
|
|
12
|
-
import
|
|
12
|
+
import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
|
|
13
|
+
import { writeAccessTokenCookie } from '#adata-ui/composables/useAccessTokenCookie'
|
|
13
14
|
|
|
14
15
|
const emit = defineEmits<{
|
|
15
16
|
(e: 'closed', value: boolean): void
|
|
@@ -35,6 +36,10 @@ const authApiURL = commonAuth.authApiURL
|
|
|
35
36
|
const accessToken = useCookie('accessToken')
|
|
36
37
|
const isAuthenticated = computed(() => !!accessToken.value)
|
|
37
38
|
|
|
39
|
+
// one-shot флаг: обмен по auth-сессии перезагружает страницу максимум один раз,
|
|
40
|
+
// иначе нечитаемая кука accessToken зацикливает reload
|
|
41
|
+
const AUTH_RELOAD_FLAG = 'auth-exchange-reloaded'
|
|
42
|
+
|
|
38
43
|
onMounted(async () => {
|
|
39
44
|
const response = await fetch(`${removeTrailingSlash(authApiURL)}/access/cookie`, {
|
|
40
45
|
method: 'GET',
|
|
@@ -46,17 +51,25 @@ onMounted(async () => {
|
|
|
46
51
|
const { data: cookiesData } = await response.json()
|
|
47
52
|
if (cookiesData?.access_token && !accessToken.value) {
|
|
48
53
|
const { access_token, expire_in } = cookiesData
|
|
49
|
-
const hostname = location.hostname.split('.').reverse()
|
|
50
54
|
useCookie('autoLogout').value = true
|
|
51
55
|
|
|
52
|
-
|
|
53
|
-
maxAge: expire_in,
|
|
54
|
-
domain: `.${hostname[1]}.${hostname[0]}`,
|
|
55
|
-
path: '/',
|
|
56
|
-
secure: true,
|
|
57
|
-
}).value = access_token
|
|
56
|
+
const persisted = await writeAccessTokenCookie(access_token, expire_in)
|
|
58
57
|
|
|
59
|
-
|
|
58
|
+
if (persisted && !sessionStorage.getItem(AUTH_RELOAD_FLAG)) {
|
|
59
|
+
sessionStorage.setItem(AUTH_RELOAD_FLAG, '1')
|
|
60
|
+
window.location.reload()
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
sessionStorage.removeItem(AUTH_RELOAD_FLAG)
|
|
64
|
+
console.warn(
|
|
65
|
+
persisted
|
|
66
|
+
? '[auth] accessToken cookie is erased between page loads (SSR resetTokens?), reload skipped to avoid a loop'
|
|
67
|
+
: '[auth] accessToken cookie was not persisted (domain/secure/maxAge rejected by browser), reload skipped',
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
sessionStorage.removeItem(AUTH_RELOAD_FLAG)
|
|
60
73
|
}
|
|
61
74
|
})
|
|
62
75
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
|
|
3
2
|
import IdOtpInput from '#adata-ui/components/modals/id/IdOtpInput.vue'
|
|
3
|
+
import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
|
|
4
|
+
import { writeAccessTokenCookie } from '#adata-ui/composables/useAccessTokenCookie'
|
|
4
5
|
import { useUrls } from '#adata-ui/composables/useUrls'
|
|
5
6
|
|
|
6
7
|
const { $toast } = useNuxtApp()
|
|
@@ -54,15 +55,9 @@ async function onConfirm() {
|
|
|
54
55
|
const { data: cookiesData } = await response.json()
|
|
55
56
|
if (cookiesData?.access_token) {
|
|
56
57
|
const { access_token, expire_in } = cookiesData
|
|
57
|
-
const hostname = location.hostname.split('.').reverse()
|
|
58
58
|
useCookie('autoLogout').value = true
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
maxAge: expire_in,
|
|
62
|
-
domain: `.${hostname[1]}.${hostname[0]}`,
|
|
63
|
-
path: '/',
|
|
64
|
-
secure: true,
|
|
65
|
-
}).value = access_token
|
|
60
|
+
await writeAccessTokenCookie(access_token, expire_in)
|
|
66
61
|
}
|
|
67
62
|
$toast.success(t('login.successfully'))
|
|
68
63
|
twoFactorModal.value = false
|
|
@@ -22,18 +22,18 @@ interface HeaderNav {
|
|
|
22
22
|
|
|
23
23
|
const navs: HeaderNav[] = [
|
|
24
24
|
{ label: 'header.navs.products', dataAttribute: 'header-products-and-solutions-button', menu: ProductMenu },
|
|
25
|
-
{ label: 'header.navs.contacts', dataAttribute: 'header-contacts-button'
|
|
25
|
+
{ label: 'header.navs.contacts', dataAttribute: 'header-contacts-button' },
|
|
26
26
|
{ label: 'header.navs.tariffs', dataAttribute: 'header-tariffs-button' },
|
|
27
27
|
]
|
|
28
28
|
|
|
29
|
-
const OPEN_DELAY = 500
|
|
30
|
-
const SWITCH_DELAY = 80
|
|
29
|
+
const OPEN_DELAY = 500
|
|
30
|
+
const SWITCH_DELAY = 80
|
|
31
31
|
|
|
32
32
|
const menu = ref<HTMLElement | null>(null)
|
|
33
33
|
const show = ref(false)
|
|
34
|
-
const locked = ref(false)
|
|
34
|
+
const locked = ref(false)
|
|
35
35
|
const currentIndex = ref(0)
|
|
36
|
-
const swapName = ref('swap-fade')
|
|
36
|
+
const swapName = ref('swap-fade')
|
|
37
37
|
const hoverTimer = ref<ReturnType<typeof setTimeout> | null>(null)
|
|
38
38
|
|
|
39
39
|
const currentMenu = computed(() => navs[currentIndex.value]?.menu ?? null)
|
|
@@ -42,8 +42,6 @@ function isActive(index: number) {
|
|
|
42
42
|
return show.value && currentIndex.value === index
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
// Open `index`'s panel. Slide toward the direction of travel when switching
|
|
46
|
-
// between already-open panels; fade (no sideways shift) on a fresh open.
|
|
47
45
|
function openMenu(index: number) {
|
|
48
46
|
swapName.value = show.value && index !== currentIndex.value
|
|
49
47
|
? (index > currentIndex.value ? 'slide-next' : 'slide-prev')
|
|
@@ -57,6 +55,10 @@ function closeMenu() {
|
|
|
57
55
|
locked.value = false
|
|
58
56
|
}
|
|
59
57
|
|
|
58
|
+
function goToContacts() {
|
|
59
|
+
navigateToLocalizedPage({ locale, projectUrl: landing, path: PAGES.contacts, target: '_blank' })
|
|
60
|
+
}
|
|
61
|
+
|
|
60
62
|
function goToTariffs() {
|
|
61
63
|
const host = useRequestURL().hostname
|
|
62
64
|
const codeMap: Record<string, string> = {
|
|
@@ -73,11 +75,15 @@ function goToTariffs() {
|
|
|
73
75
|
navigateToLocalizedPage({ locale, projectUrl: landing, path: PAGES.tariffs + code, target: '_blank' })
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
// Click pins the menu open; items without a menu (Tariffs) navigate instead.
|
|
77
78
|
function toggleMenu(index: number) {
|
|
78
79
|
const nav = navs[index]
|
|
79
80
|
if (!nav?.menu) {
|
|
80
|
-
|
|
81
|
+
if (index === 1) {
|
|
82
|
+
goToContacts()
|
|
83
|
+
}
|
|
84
|
+
else if (index === 2) {
|
|
85
|
+
goToTariffs()
|
|
86
|
+
}
|
|
81
87
|
return
|
|
82
88
|
}
|
|
83
89
|
if (show.value && currentIndex.value === index) {
|
|
@@ -95,7 +101,6 @@ function clearHoverTimer() {
|
|
|
95
101
|
}
|
|
96
102
|
}
|
|
97
103
|
|
|
98
|
-
// Hover opens menu items; hovering Tariffs dismisses an unpinned menu.
|
|
99
104
|
function scheduleOpen(index: number) {
|
|
100
105
|
clearHoverTimer()
|
|
101
106
|
hoverTimer.value = setTimeout(() => {
|
|
@@ -104,14 +109,10 @@ function scheduleOpen(index: number) {
|
|
|
104
109
|
}, show.value ? SWITCH_DELAY : OPEN_DELAY)
|
|
105
110
|
}
|
|
106
111
|
|
|
107
|
-
// Overlay closes on click regardless of the pin; on hover only while unpinned.
|
|
108
112
|
function onOverlayHover() {
|
|
109
113
|
if (!locked.value) closeMenu()
|
|
110
114
|
}
|
|
111
115
|
|
|
112
|
-
// Lock body scroll while the mega-menu is open. `scrollbar-gutter: stable` is set
|
|
113
|
-
// globally, so we don't reserve the gap to avoid a double-compensated page shift.
|
|
114
|
-
// The panel is mounted via v-if, so wait a tick for the ref on open.
|
|
115
116
|
watch(show, async (open) => {
|
|
116
117
|
if (open) {
|
|
117
118
|
await nextTick()
|
|
@@ -157,7 +158,6 @@ onBeforeUnmount(() => {
|
|
|
157
158
|
</li>
|
|
158
159
|
</ul>
|
|
159
160
|
|
|
160
|
-
<!-- One transition drives the whole panel's open/close (appear + disappear). -->
|
|
161
161
|
<transition name="menu">
|
|
162
162
|
<div
|
|
163
163
|
v-if="show"
|
|
@@ -165,14 +165,12 @@ onBeforeUnmount(() => {
|
|
|
165
165
|
class="fixed inset-x-0 z-20"
|
|
166
166
|
:style="{ top: `${menuTop}px`, height: `calc(100dvh - ${menuTop}px)` }"
|
|
167
167
|
>
|
|
168
|
-
<!-- Full-page dimmed blur backdrop behind the panel. -->
|
|
169
168
|
<div
|
|
170
169
|
class="absolute inset-0 bg-gray-900/30 backdrop-blur dark:bg-black/50"
|
|
171
170
|
@click="closeMenu"
|
|
172
171
|
@mouseover="onOverlayHover"
|
|
173
172
|
/>
|
|
174
173
|
|
|
175
|
-
<!-- Panel on top; slides left/right when switching between menu items. -->
|
|
176
174
|
<transition
|
|
177
175
|
:name="swapName"
|
|
178
176
|
mode="out-in"
|
|
@@ -181,7 +179,6 @@ onBeforeUnmount(() => {
|
|
|
181
179
|
:is="currentMenu"
|
|
182
180
|
:key="currentIndex"
|
|
183
181
|
class="relative"
|
|
184
|
-
:url="buildLocalizedUrl(locale, landing, PAGES.contacts)"
|
|
185
182
|
/>
|
|
186
183
|
</transition>
|
|
187
184
|
</div>
|
|
@@ -193,7 +190,6 @@ onBeforeUnmount(() => {
|
|
|
193
190
|
$ease: cubic-bezier(0.22, 1, 0.36, 1);
|
|
194
191
|
$shift: 24px;
|
|
195
192
|
|
|
196
|
-
// Whole menu: open and close (vertical fade, no horizontal motion).
|
|
197
193
|
.menu-enter-active,
|
|
198
194
|
.menu-leave-active {
|
|
199
195
|
transition:
|
|
@@ -207,7 +203,6 @@ $shift: 24px;
|
|
|
207
203
|
transform: translateY(-12px);
|
|
208
204
|
}
|
|
209
205
|
|
|
210
|
-
// Switching panels: slide toward the direction of travel (out-in, so no overlap).
|
|
211
206
|
.slide-next-enter-active,
|
|
212
207
|
.slide-next-leave-active,
|
|
213
208
|
.slide-prev-enter-active,
|
|
@@ -239,7 +234,6 @@ $shift: 24px;
|
|
|
239
234
|
transform: translateX($shift);
|
|
240
235
|
}
|
|
241
236
|
|
|
242
|
-
// Fresh open (no switch): fade only, so the panel never slides sideways.
|
|
243
237
|
.swap-fade-enter-from,
|
|
244
238
|
.swap-fade-leave-to {
|
|
245
239
|
opacity: 0;
|
|
@@ -27,19 +27,14 @@ function isActive(itemPath: string) {
|
|
|
27
27
|
</script>
|
|
28
28
|
|
|
29
29
|
<template>
|
|
30
|
-
<section
|
|
31
|
-
class="group/section overflow-hidden rounded-xl border p-3 shadow-sm transition-colors"
|
|
32
|
-
:class="currentModule
|
|
33
|
-
? 'border-blue-700/20 bg-blue-50 hover:border-blue-700/40 dark:border-blue-500/20 dark:bg-blue-500/5 dark:hover:border-blue-500/40'
|
|
34
|
-
: 'border-gray-200 bg-white hover:border-blue-700/40 dark:border-gray-800 dark:bg-gray-950 dark:hover:border-blue-500/40'"
|
|
35
|
-
>
|
|
30
|
+
<section class="group/section overflow-hidden flex flex-col ">
|
|
36
31
|
<div class="mb-3 flex items-start justify-between gap-2">
|
|
37
32
|
<nuxt-link-locale
|
|
38
33
|
:to="link"
|
|
39
|
-
class="group/title flex min-w-0 items-center gap-2 text-
|
|
34
|
+
class="group/title flex min-w-0 items-center gap-2 text-base font-semibold text-deepblue-900 transition-colors hover:text-blue-700 dark:text-gray-100 dark:hover:text-blue-500"
|
|
40
35
|
>
|
|
41
36
|
<span
|
|
42
|
-
class="flex size-8 shrink-0 items-center justify-center rounded-lg bg-blue-
|
|
37
|
+
class="flex size-8 shrink-0 items-center justify-center rounded-lg bg-blue-50 text-blue-500 transition-colors group-hover/title:bg-blue-700 group-hover/title:text-white dark:bg-blue-500/10 dark:text-blue-500 dark:group-hover/title:bg-blue-500">
|
|
43
38
|
<component
|
|
44
39
|
:is="icon"
|
|
45
40
|
class="size-4"
|
|
@@ -47,15 +42,6 @@ function isActive(itemPath: string) {
|
|
|
47
42
|
</span>
|
|
48
43
|
<span class="block truncate normal-case">{{ title }}</span>
|
|
49
44
|
</nuxt-link-locale>
|
|
50
|
-
|
|
51
|
-
<div class="flex shrink-0 items-center gap-1">
|
|
52
|
-
<span
|
|
53
|
-
v-if="badge"
|
|
54
|
-
class="rounded-full bg-blue-700/10 px-1.5 py-0.5 text-[10px] font-bold uppercase leading-none text-blue-700 dark:bg-blue-500/10 dark:text-blue-500"
|
|
55
|
-
>NEW</span>
|
|
56
|
-
<a-icon-arrow-side-up
|
|
57
|
-
class="size-4 text-gray-500 transition-colors group-hover/section:text-blue-700 dark:group-hover/section:text-blue-500"/>
|
|
58
|
-
</div>
|
|
59
45
|
</div>
|
|
60
46
|
|
|
61
47
|
<ul class="grid gap-1">
|
|
@@ -67,24 +53,12 @@ function isActive(itemPath: string) {
|
|
|
67
53
|
v-if="item.to"
|
|
68
54
|
:to="item.to"
|
|
69
55
|
itemprop="name"
|
|
70
|
-
class="group/item flex items-center gap-2 rounded-lg px-2 py-1.5 transition-colors hover:bg-
|
|
56
|
+
class="group/item flex items-center gap-2 rounded-lg px-2 py-1.5 transition-colors hover:bg-gray-50 dark:hover:bg-gray-200/10"
|
|
71
57
|
:class="{ 'bg-blue-100 dark:bg-gray-200/10': isActive(item.to) }"
|
|
72
58
|
>
|
|
59
|
+
<a-icon-chevron-right class="size-[14px] shrink-0 text-gray-300 group-hover/item:text-blue-500 dark:group-hover/item:text-blue-700" />
|
|
73
60
|
<span
|
|
74
|
-
class="
|
|
75
|
-
:class="{
|
|
76
|
-
'bg-blue-700/10 text-blue-700 dark:bg-blue-500/10 dark:text-blue-500': isActive(item.to),
|
|
77
|
-
'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-300': !isActive(item.to),
|
|
78
|
-
// 'bg-white text-gray-600 dark:bg-white dark:text-gray-300': currentModule,
|
|
79
|
-
}"
|
|
80
|
-
>
|
|
81
|
-
<component
|
|
82
|
-
:is="item.icon"
|
|
83
|
-
class="size-[14px]"
|
|
84
|
-
/>
|
|
85
|
-
</span>
|
|
86
|
-
<span
|
|
87
|
-
class="truncate text-sm font-semibold normal-case transition-colors group-hover/item:text-deepblue-900 dark:group-hover/item:text-gray-100"
|
|
61
|
+
class="min-w-0 text-sm normal-case transition-colors group-hover/item:text-deepblue-900 group-hover/item:font-semibold dark:group-hover/item:text-gray-100"
|
|
88
62
|
:class="isActive(item.to)
|
|
89
63
|
? 'text-blue-700 dark:text-blue-500'
|
|
90
64
|
: 'text-gray-600 dark:text-gray-300'"
|
|
@@ -92,5 +66,7 @@ function isActive(itemPath: string) {
|
|
|
92
66
|
</nuxt-link-locale>
|
|
93
67
|
</li>
|
|
94
68
|
</ul>
|
|
69
|
+
|
|
70
|
+
<slot name="bottom" />
|
|
95
71
|
</section>
|
|
96
72
|
</template>
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import CardGallery from '#adata-ui/components/navigation/header/CardGallery.vue'
|
|
3
2
|
import NavList from '#adata-ui/components/navigation/header/NavList.vue'
|
|
4
3
|
import { useActiveNavigation } from '#adata-ui/composables/useActiveNavigation'
|
|
5
4
|
import { useHeaderNavigationLinks } from '#adata-ui/composables/useHeaderNavigationLinks'
|
|
5
|
+
import { PAGES } from '#adata-ui/shared/constans/pages'
|
|
6
|
+
import { useUrls } from '#adata-ui/composables/useUrls'
|
|
7
|
+
import AIconArrowRight from '#adata-ui/icons/arrow/arrow-right.vue'
|
|
8
|
+
import AIconDownloadRounded from '#adata-ui/icons/download-rounded.vue'
|
|
6
9
|
|
|
7
10
|
defineProps<{ url?: string }>()
|
|
8
11
|
defineEmits(['outerClick', 'mouseOver'])
|
|
9
12
|
|
|
10
|
-
const
|
|
13
|
+
const urls = useUrls()
|
|
14
|
+
const { t, locale } = useI18n()
|
|
11
15
|
const modules = useHeaderNavigationLinks()
|
|
12
16
|
const { isActiveModule } = useActiveNavigation()
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
const edoModule = computed(() => modules.value.find(module => module.key === 'edo') ?? null)
|
|
16
|
-
|
|
17
|
-
const COLUMN_KEYS = [['pk', 'fines', 'work'], ['fea', 'tenders'], ['compliance', 'analytics']]
|
|
18
|
+
const COLUMN_KEYS = [['edo'], ['pk'], ['compliance', 'fines'], ['tenders', 'analytics'], ['fea', 'work']]
|
|
18
19
|
const catalogColumns = computed(() =>
|
|
19
20
|
COLUMN_KEYS.map(keys =>
|
|
20
21
|
keys
|
|
@@ -22,6 +23,14 @@ const catalogColumns = computed(() =>
|
|
|
22
23
|
.filter((module): module is NonNullable<typeof module> => module !== undefined),
|
|
23
24
|
),
|
|
24
25
|
)
|
|
26
|
+
|
|
27
|
+
function handleExportClick() {
|
|
28
|
+
navigateToLocalizedPage({
|
|
29
|
+
locale: locale.value,
|
|
30
|
+
projectUrl: urls.pk,
|
|
31
|
+
path: PAGES.pk.unload,
|
|
32
|
+
})
|
|
33
|
+
}
|
|
25
34
|
</script>
|
|
26
35
|
|
|
27
36
|
<template>
|
|
@@ -29,52 +38,12 @@ const catalogColumns = computed(() =>
|
|
|
29
38
|
<div class="relative bg-white dark:bg-gray-950">
|
|
30
39
|
<div class="a-container max-h-[calc(100dvh-4rem)] overflow-y-auto overscroll-contain py-8">
|
|
31
40
|
<div class="flex justify-between gap-5">
|
|
32
|
-
|
|
33
|
-
<aside class="flex w-[320px] shrink-0 flex-col gap-5">
|
|
34
|
-
<nuxt-link-locale
|
|
35
|
-
v-if="edoModule"
|
|
36
|
-
:to="edoModule.link"
|
|
37
|
-
class="group block overflow-hidden rounded-xl border border-blue-700/20 p-4 shadow-sm transition-colors hover:border-blue-700/40 hover:bg-blue-100 dark:border-blue-500/20 dark:hover:border-blue-500/40 dark:hover:bg-blue-500/10"
|
|
38
|
-
:data-test-id="edoModule.data_attribute"
|
|
39
|
-
>
|
|
40
|
-
<div class="flex items-start gap-3">
|
|
41
|
-
<div
|
|
42
|
-
class="flex size-10 shrink-0 items-center justify-center rounded-lg bg-blue-700 text-white shadow-sm">
|
|
43
|
-
<component
|
|
44
|
-
:is="edoModule.icon"
|
|
45
|
-
class="size-5"
|
|
46
|
-
/>
|
|
47
|
-
</div>
|
|
48
|
-
<div class="min-w-0">
|
|
49
|
-
<div class="flex items-center justify-between gap-2">
|
|
50
|
-
<h3 class="text-base font-bold normal-case text-deepblue-900 dark:text-gray-100">
|
|
51
|
-
{{ edoModule.name }}
|
|
52
|
-
</h3>
|
|
53
|
-
<div class="flex items-center gap-1 justify-end">
|
|
54
|
-
<span
|
|
55
|
-
v-if="edoModule.is_new"
|
|
56
|
-
class="rounded-full bg-blue-700/10 px-1.5 py-0.5 text-[10px] font-bold uppercase leading-none text-blue-700 dark:bg-blue-500/10 dark:text-blue-500"
|
|
57
|
-
>NEW</span>
|
|
58
|
-
<a-icon-arrow-side-up
|
|
59
|
-
class="size-4 text-gray-500 transition group-hover:-translate-y-0.5 group-hover:translate-x-0.5 group-hover:text-blue-700 dark:text-gray-400 dark:group-hover:text-blue-500"/>
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
<p class="mt-1 text-sm normal-case leading-snug text-gray-600 dark:text-gray-300">
|
|
63
|
-
{{ t('header.products.edo.heroSubtitle') }}
|
|
64
|
-
</p>
|
|
65
|
-
</div>
|
|
66
|
-
</div>
|
|
67
|
-
</nuxt-link-locale>
|
|
68
|
-
|
|
69
|
-
<card-gallery class="hidden lg:block"/>
|
|
70
|
-
</aside>
|
|
71
|
-
|
|
72
|
-
<!-- Catalog grid: products as bordered section cards (EDO lives in the hero). -->
|
|
73
|
-
<div class="grid min-w-0 flex-1 grid-cols-3 gap-3">
|
|
41
|
+
<div class="grid min-w-0 flex-1 grid-cols-5 gap-x-3 gap-y-3">
|
|
74
42
|
<div
|
|
75
43
|
v-for="(column, index) in catalogColumns"
|
|
76
44
|
:key="index"
|
|
77
|
-
class="flex flex-col gap-
|
|
45
|
+
class="flex flex-col gap-[22px]"
|
|
46
|
+
:class="index > 0 ? 'border-l border-gray-100 pl-3 dark:border-gray-800' : ''"
|
|
78
47
|
>
|
|
79
48
|
<nav-list
|
|
80
49
|
v-for="module in column"
|
|
@@ -88,7 +57,40 @@ const catalogColumns = computed(() =>
|
|
|
88
57
|
:icon="module.icon"
|
|
89
58
|
:badge="module.is_new"
|
|
90
59
|
:data-test-id="module.data_attribute"
|
|
91
|
-
|
|
60
|
+
>
|
|
61
|
+
<template
|
|
62
|
+
v-if="module.key === 'edo'"
|
|
63
|
+
#bottom
|
|
64
|
+
>
|
|
65
|
+
<div class="mt-4 flex flex-col gap-4 rounded-xl bg-blue-700 dark:bg-blue-500 p-4 text-white normal-case">
|
|
66
|
+
<div class="flex items-center gap-3">
|
|
67
|
+
<span class="p-[10px] bg-white rounded-[10px] dark:bg-gray-950">
|
|
68
|
+
<AIconDownloadRounded class="size-5 text-blue-700 dark:text-blue-500" />
|
|
69
|
+
</span>
|
|
70
|
+
<span class="font-semibold text-white dark:text-gray-950">
|
|
71
|
+
{{ t('header.products.exportCard.title') }}
|
|
72
|
+
</span>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<div class="text-xs text-white dark:text-gray-950">
|
|
76
|
+
{{ t('header.products.exportCard.subTitle') }}
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<a-button-v2
|
|
80
|
+
view="soft"
|
|
81
|
+
class="!h-9 w-fit !bg-white dark:!bg-gray-950 text-blue-700 dark:text-blue-500"
|
|
82
|
+
size="sm"
|
|
83
|
+
:icon="AIconArrowRight"
|
|
84
|
+
icon-right
|
|
85
|
+
@click="handleExportClick"
|
|
86
|
+
>
|
|
87
|
+
<span class="text-sm">
|
|
88
|
+
{{ t('header.products.exportCard.receive') }}
|
|
89
|
+
</span>
|
|
90
|
+
</a-button-v2>
|
|
91
|
+
</div>
|
|
92
|
+
</template>
|
|
93
|
+
</nav-list>
|
|
92
94
|
</div>
|
|
93
95
|
</div>
|
|
94
96
|
</div>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useUrls } from '#adata-ui/composables/useUrls'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Единая точка записи куки accessToken (логин, 2FA, OTP, обмен по auth-сессии).
|
|
5
|
+
* Домен должен совпадать с доменом удаления в resetTokens (adata-common-auth),
|
|
6
|
+
* иначе кука не находится на следующей загрузке и логин-флоу зацикливается на reload.
|
|
7
|
+
*/
|
|
8
|
+
export async function writeAccessTokenCookie(accessToken: string, expireIn?: number): Promise<boolean> {
|
|
9
|
+
const { mode } = useUrls()
|
|
10
|
+
const sharedDomain = `${mode}.kz`
|
|
11
|
+
const onSharedDomain = location.hostname === sharedDomain || location.hostname.endsWith(`.${sharedDomain}`)
|
|
12
|
+
const maxAge = Number(expireIn) > 0 ? Number(expireIn) : undefined
|
|
13
|
+
|
|
14
|
+
useCookie('accessToken', {
|
|
15
|
+
maxAge,
|
|
16
|
+
// на localhost/превью-хостах атрибут domain невалиден — пишем host-only куку
|
|
17
|
+
domain: onSharedDomain ? `.${sharedDomain}` : undefined,
|
|
18
|
+
path: '/',
|
|
19
|
+
secure: location.protocol === 'https:',
|
|
20
|
+
}).value = accessToken
|
|
21
|
+
|
|
22
|
+
// useCookie пишет document.cookie на следующем flush, не синхронно
|
|
23
|
+
await nextTick()
|
|
24
|
+
return document.cookie.split('; ').some(part => part.startsWith('accessToken='))
|
|
25
|
+
}
|
|
@@ -4,6 +4,7 @@ interface UseChipOverflowOptions {
|
|
|
4
4
|
container: Ref<HTMLElement | null>
|
|
5
5
|
measure: Ref<HTMLElement | null>
|
|
6
6
|
count: Ref<number>
|
|
7
|
+
contentKey?: Ref<unknown>
|
|
7
8
|
gap?: number
|
|
8
9
|
}
|
|
9
10
|
|
|
@@ -13,11 +14,17 @@ interface UseChipOverflow {
|
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export function useChipOverflow(options: UseChipOverflowOptions): UseChipOverflow {
|
|
16
|
-
const { container, measure, count, gap = 6 } = options
|
|
17
|
+
const { container, measure, count, contentKey, gap = 6 } = options
|
|
17
18
|
|
|
18
19
|
const availableWidth = ref(0)
|
|
19
20
|
const visibleCount = ref(0)
|
|
20
21
|
|
|
22
|
+
// Ceil so a chip is only counted as fitting when it fully fits;
|
|
23
|
+
// sub-pixel underestimates would let flexbox squeeze visible chips into truncation.
|
|
24
|
+
function chipWidth(el: HTMLElement): number {
|
|
25
|
+
return Math.ceil(el.getBoundingClientRect().width)
|
|
26
|
+
}
|
|
27
|
+
|
|
21
28
|
function recompute() {
|
|
22
29
|
const total = count.value
|
|
23
30
|
if (total <= 0) {
|
|
@@ -38,7 +45,7 @@ export function useChipOverflow(options: UseChipOverflowOptions): UseChipOverflo
|
|
|
38
45
|
let used = 0
|
|
39
46
|
let fit = 0
|
|
40
47
|
for (let i = 0; i < chips.length; i++) {
|
|
41
|
-
const width = chips[i]
|
|
48
|
+
const width = chipWidth(chips[i]) + (i > 0 ? gap : 0)
|
|
42
49
|
if (used + width > avail) break
|
|
43
50
|
used += width
|
|
44
51
|
fit++
|
|
@@ -50,9 +57,9 @@ export function useChipOverflow(options: UseChipOverflowOptions): UseChipOverflo
|
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
const badge = root.children[total] as HTMLElement | undefined
|
|
53
|
-
const badgeWidth = (badge
|
|
60
|
+
const badgeWidth = (badge ? chipWidth(badge) : 0) + gap
|
|
54
61
|
while (fit > 1 && used + badgeWidth > avail) {
|
|
55
|
-
used -= chips[fit - 1]
|
|
62
|
+
used -= chipWidth(chips[fit - 1]) + gap
|
|
56
63
|
fit--
|
|
57
64
|
}
|
|
58
65
|
|
|
@@ -63,9 +70,9 @@ export function useChipOverflow(options: UseChipOverflowOptions): UseChipOverflo
|
|
|
63
70
|
|
|
64
71
|
onMounted(() => {
|
|
65
72
|
if (container.value) {
|
|
66
|
-
availableWidth.value = container.value.clientWidth
|
|
73
|
+
availableWidth.value = Math.floor(container.value.clientWidth)
|
|
67
74
|
resizeObserver = new ResizeObserver((entries) => {
|
|
68
|
-
availableWidth.value = entries[0]?.contentRect.width ?? 0
|
|
75
|
+
availableWidth.value = Math.floor(entries[0]?.contentRect.width ?? 0)
|
|
69
76
|
})
|
|
70
77
|
resizeObserver.observe(container.value)
|
|
71
78
|
}
|
|
@@ -74,7 +81,10 @@ export function useChipOverflow(options: UseChipOverflowOptions): UseChipOverflo
|
|
|
74
81
|
|
|
75
82
|
onUnmounted(() => resizeObserver?.disconnect())
|
|
76
83
|
|
|
77
|
-
watch(
|
|
84
|
+
watch(
|
|
85
|
+
contentKey ? [availableWidth, count, contentKey] : [availableWidth, count],
|
|
86
|
+
() => nextTick(recompute),
|
|
87
|
+
)
|
|
78
88
|
|
|
79
89
|
const hiddenCount = computed(() => Math.max(0, count.value - visibleCount.value))
|
|
80
90
|
|
|
@@ -9,12 +9,9 @@ import IconBlock from '#adata-ui/icons/block.vue'
|
|
|
9
9
|
import IconDollar from '#adata-ui/icons/currency/currency-dollar.vue'
|
|
10
10
|
import IconWork from '#adata-ui/icons/work-bag.vue'
|
|
11
11
|
import IconDocument from '#adata-ui/icons/hdocument.vue'
|
|
12
|
-
import IconCheck from '#adata-ui/icons/hcheck.vue'
|
|
13
|
-
import IconFile from '#adata-ui/icons/file/file.vue'
|
|
14
12
|
import IconCheckCircle from '#adata-ui/icons/check/check-circle.vue'
|
|
15
13
|
import IconCar from '#adata-ui/icons/car.vue'
|
|
16
14
|
import IconTruck from '#adata-ui/icons/truck.vue'
|
|
17
|
-
import IconClipboardText from '#adata-ui/icons/clipboard-text.vue'
|
|
18
15
|
import IconArrowGraph from '#adata-ui/icons/arrow/arrow-graph-up.vue'
|
|
19
16
|
import IconMedal from '#adata-ui/icons/medal.vue'
|
|
20
17
|
import IconCompany from '#adata-ui/icons/company.vue'
|
|
@@ -26,24 +23,27 @@ import { buildLocalizedUrl } from '#adata-ui/utils/localizedNavigation'
|
|
|
26
23
|
import IconLock from '#adata-ui/icons/lock.vue'
|
|
27
24
|
import IconReceipt from '#adata-ui/icons/receipt.vue'
|
|
28
25
|
import IconFavorite from '#adata-ui/icons/bookmark/bookmark.vue'
|
|
29
|
-
// import IconReport from '#adata-ui/icons/file/file.vue'
|
|
30
26
|
import IconHistory from '#adata-ui/icons/history.vue'
|
|
31
27
|
import IconMessage from '#adata-ui/icons/message/message.vue'
|
|
28
|
+
import AIconBriefcase from '#adata-ui/icons/briefcase.vue'
|
|
29
|
+
import AIconCarSide from '#adata-ui/icons/car-side.vue'
|
|
30
|
+
import AIconShieldVerified from '#adata-ui/icons/shield-verified.vue'
|
|
31
|
+
import AIconCart from '#adata-ui/icons/cart.vue'
|
|
32
32
|
import {
|
|
33
|
-
AIconWorkBag,
|
|
34
33
|
AIconUsersThree,
|
|
35
|
-
AIconReceipt,
|
|
36
|
-
AIconCar,
|
|
37
34
|
AIconArrowGraphUp,
|
|
38
35
|
AIconGlobe,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
AIconArrowSquareDown,
|
|
37
|
+
AIconExpandWindow,
|
|
38
|
+
AIconUsers,
|
|
39
|
+
AIconWarningTriangle,
|
|
40
|
+
AIconSearch,
|
|
41
|
+
AIconAkimat,
|
|
42
|
+
AIconCurrencyTenge,
|
|
43
|
+
AIconExcelIcon,
|
|
42
44
|
} from '#components'
|
|
43
45
|
import MapPinRect from '#adata-ui/icons/map/map-pin-rect.vue'
|
|
44
46
|
import MapPaper from '#adata-ui/icons/map-paper.vue'
|
|
45
|
-
import ChartBar from '#adata-ui/icons/chart-bar.vue'
|
|
46
|
-
import Bank from '#adata-ui/icons/bank.vue'
|
|
47
47
|
import { useUrls } from '#adata-ui/composables/useUrls'
|
|
48
48
|
import AiAssistant from '#adata-ui/icons/ai-assistant.vue'
|
|
49
49
|
import Tasks from '#adata-ui/icons/tasks.vue'
|
|
@@ -61,7 +61,7 @@ export const useHeaderNavigationLinks = () => {
|
|
|
61
61
|
key: 'pk',
|
|
62
62
|
name: t('header.products.counterparties.label'),
|
|
63
63
|
link: buildLocalizedUrl(locale, urls.pk, PAGES.pk.main),
|
|
64
|
-
icon:
|
|
64
|
+
icon: AIconUsers,
|
|
65
65
|
to: urls.pk,
|
|
66
66
|
data_attribute: 'navigation-menu-counterparty-block',
|
|
67
67
|
items: [
|
|
@@ -115,7 +115,7 @@ export const useHeaderNavigationLinks = () => {
|
|
|
115
115
|
key: 'fines',
|
|
116
116
|
name: t('header.products.fines.label'),
|
|
117
117
|
link: buildLocalizedUrl(locale, urls.avto, PAGES.fines.main),
|
|
118
|
-
icon:
|
|
118
|
+
icon: AIconCarSide,
|
|
119
119
|
data_attribute: 'navigation-menu-fines-block',
|
|
120
120
|
items: [
|
|
121
121
|
{
|
|
@@ -142,7 +142,7 @@ export const useHeaderNavigationLinks = () => {
|
|
|
142
142
|
key: 'work',
|
|
143
143
|
name: t('header.products.jobs.label'),
|
|
144
144
|
link: urls.work,
|
|
145
|
-
icon:
|
|
145
|
+
icon: AIconBriefcase,
|
|
146
146
|
data_attribute: 'navigation-menu-work-block',
|
|
147
147
|
items: [
|
|
148
148
|
{
|
|
@@ -216,7 +216,7 @@ export const useHeaderNavigationLinks = () => {
|
|
|
216
216
|
key: 'tenders',
|
|
217
217
|
name: t('header.products.tenders.label'),
|
|
218
218
|
link: urls.zakupki,
|
|
219
|
-
icon:
|
|
219
|
+
icon: AIconCart,
|
|
220
220
|
is_new: true,
|
|
221
221
|
to: urls.tender,
|
|
222
222
|
data_attribute: 'navigation-menu-zakupki-block',
|
|
@@ -264,15 +264,39 @@ export const useHeaderNavigationLinks = () => {
|
|
|
264
264
|
is_new: true,
|
|
265
265
|
name: t('header.products.edo.label'),
|
|
266
266
|
link: buildLocalizedUrl(locale, urls.edo_docs , ''),
|
|
267
|
-
icon:
|
|
267
|
+
icon: AIconUsers,
|
|
268
268
|
data_attribute: 'navigation-menu-edo-block',
|
|
269
269
|
items: [
|
|
270
270
|
{
|
|
271
|
-
title: t('header.products.edo.items.
|
|
272
|
-
subtitle: t('header.products.edo.items.
|
|
273
|
-
icon:
|
|
274
|
-
to: buildLocalizedUrl(locale, urls.edo_docs ,
|
|
275
|
-
}
|
|
271
|
+
title: t('header.products.edo.items.docSign.t'),
|
|
272
|
+
subtitle: t('header.products.edo.items.docSign.st'),
|
|
273
|
+
icon: AIconUsers,
|
|
274
|
+
to: buildLocalizedUrl(locale, urls.edo_docs , PAGES.edo.docSign)
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
title: t('header.products.edo.items.docTemplate.t'),
|
|
278
|
+
subtitle: t('header.products.edo.items.docTemplate.st'),
|
|
279
|
+
icon: AIconUsers,
|
|
280
|
+
to: buildLocalizedUrl(locale, urls.edo_docs , PAGES.edo.docTemplate)
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
title: t('header.products.edo.items.docRisk.t'),
|
|
284
|
+
subtitle: t('header.products.edo.items.docRisk.st'),
|
|
285
|
+
icon: AIconUsers,
|
|
286
|
+
to: buildLocalizedUrl(locale, urls.edo_docs , PAGES.edo.docRisk)
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
title: t('header.products.edo.items.docCompare.t'),
|
|
290
|
+
subtitle: t('header.products.edo.items.docCompare.st'),
|
|
291
|
+
icon: AIconUsers,
|
|
292
|
+
to: buildLocalizedUrl(locale, urls.edo_docs , PAGES.edo.docCompare)
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
title: t('header.products.edo.items.docAi.t'),
|
|
296
|
+
subtitle: t('header.products.edo.items.docAi.st'),
|
|
297
|
+
icon: AIconUsers,
|
|
298
|
+
to: buildLocalizedUrl(locale, urls.edo_docs , PAGES.edo.docAi)
|
|
299
|
+
},
|
|
276
300
|
]
|
|
277
301
|
},
|
|
278
302
|
{
|
|
@@ -280,7 +304,7 @@ export const useHeaderNavigationLinks = () => {
|
|
|
280
304
|
is_new: true,
|
|
281
305
|
name: t('header.products.compliance.label'),
|
|
282
306
|
link: buildLocalizedUrl(locale, urls.compliance, PAGES.compliance.l),
|
|
283
|
-
icon:
|
|
307
|
+
icon: AIconShieldVerified,
|
|
284
308
|
data_attribute: 'navigation-menu-compliance-block',
|
|
285
309
|
items: [
|
|
286
310
|
{
|
|
@@ -352,6 +376,12 @@ export const useHeaderNavigationLinks = () => {
|
|
|
352
376
|
subtitle: t('header.products.analytics.items.subjects.subtitle'),
|
|
353
377
|
icon: IconCompany,
|
|
354
378
|
to: buildLocalizedUrl(locale, urls.analytics, PAGES.analytics.business)
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
title: t('header.products.analytics.items.demography.title'),
|
|
382
|
+
subtitle: t('header.products.analytics.items.demography.subtitle'),
|
|
383
|
+
icon: IconCompany,
|
|
384
|
+
to: buildLocalizedUrl(locale, urls.analytics, PAGES.analytics.demography)
|
|
355
385
|
}
|
|
356
386
|
]
|
|
357
387
|
},
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7
|
+
<path d="M3.125 7.5H11.875" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
|
8
|
+
<path d="M7.5 3.125L11.875 7.5L7.5 11.875" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
|
9
|
+
</svg>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<style scoped>
|
|
13
|
+
|
|
14
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7
|
+
<path d="M15 5.25H3C2.17157 5.25 1.5 5.92157 1.5 6.75V14.25C1.5 15.0784 2.17157 15.75 3 15.75H15C15.8284 15.75 16.5 15.0784 16.5 14.25V6.75C16.5 5.92157 15.8284 5.25 15 5.25Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
8
|
+
<path d="M12 15.75V3.75C12 3.35218 11.842 2.97064 11.5607 2.68934C11.2794 2.40804 10.8978 2.25 10.5 2.25H7.5C7.10218 2.25 6.72064 2.40804 6.43934 2.68934C6.15804 2.97064 6 3.35218 6 3.75V15.75" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
9
|
+
</svg>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<style scoped>
|
|
13
|
+
|
|
14
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7
|
+
<path d="M14.25 12.75H15.75C16.2 12.75 16.5 12.45 16.5 12V9.75C16.5 9.075 15.975 8.475 15.375 8.325C14.025 7.95 12 7.5 12 7.5C12 7.5 11.025 6.45 10.35 5.775C9.975 5.475 9.525 5.25 9 5.25H3.75C3.3 5.25 2.925 5.55 2.7 5.925L1.65 8.1C1.55068 8.38967 1.5 8.69378 1.5 9V12C1.5 12.45 1.8 12.75 2.25 12.75H3.75" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
8
|
+
<path d="M5.25 14.25C6.07843 14.25 6.75 13.5784 6.75 12.75C6.75 11.9216 6.07843 11.25 5.25 11.25C4.42157 11.25 3.75 11.9216 3.75 12.75C3.75 13.5784 4.42157 14.25 5.25 14.25Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
9
|
+
<path d="M6.75 12.75H11.25" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
10
|
+
<path d="M12.75 14.25C13.5784 14.25 14.25 13.5784 14.25 12.75C14.25 11.9216 13.5784 11.25 12.75 11.25C11.9216 11.25 11.25 11.9216 11.25 12.75C11.25 13.5784 11.9216 14.25 12.75 14.25Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
11
|
+
</svg>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<style scoped>
|
|
15
|
+
|
|
16
|
+
</style>
|
package/icons/cart.vue
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7
|
+
<path d="M6 16.5C6.41421 16.5 6.75 16.1642 6.75 15.75C6.75 15.3358 6.41421 15 6 15C5.58579 15 5.25 15.3358 5.25 15.75C5.25 16.1642 5.58579 16.5 6 16.5Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
8
|
+
<path d="M14.25 16.5C14.6642 16.5 15 16.1642 15 15.75C15 15.3358 14.6642 15 14.25 15C13.8358 15 13.5 15.3358 13.5 15.75C13.5 16.1642 13.8358 16.5 14.25 16.5Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
9
|
+
<path d="M1.53748 1.53748H3.03748L5.03248 10.8525C5.10566 11.1936 5.29548 11.4986 5.56926 11.7149C5.84304 11.9312 6.18366 12.0452 6.53248 12.0375H13.8675C14.2089 12.0369 14.5398 11.9199 14.8057 11.7059C15.0717 11.4918 15.2566 11.1934 15.33 10.86L16.5675 5.28748H3.83998" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
10
|
+
</svg>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<style scoped>
|
|
14
|
+
|
|
15
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7
|
+
<path d="M17.5 12.5V15.8333C17.5 16.2754 17.3244 16.6993 17.0118 17.0118C16.6993 17.3244 16.2754 17.5 15.8333 17.5H4.16667C3.72464 17.5 3.30072 17.3244 2.98816 17.0118C2.67559 16.6993 2.5 16.2754 2.5 15.8333V12.5" stroke="currentColor" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
|
|
8
|
+
<path d="M5.83334 8.33337L10 12.5L14.1667 8.33337" stroke="currentColor" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
|
|
9
|
+
<path d="M10 12.5V2.5" stroke="currentColor" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
|
|
10
|
+
</svg>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<style scoped>
|
|
14
|
+
|
|
15
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7
|
+
<path d="M15 9.74997C15 13.5 12.375 15.375 9.255 16.4625C9.09162 16.5178 8.91415 16.5152 8.7525 16.455C5.625 15.375 3 13.5 3 9.74997V4.49997C3 4.30106 3.07902 4.11029 3.21967 3.96964C3.36032 3.82899 3.55109 3.74997 3.75 3.74997C5.25 3.74997 7.125 2.84997 8.43 1.70997C8.58889 1.57422 8.79102 1.49963 9 1.49963C9.20898 1.49963 9.41111 1.57422 9.57 1.70997C10.8825 2.85747 12.75 3.74997 14.25 3.74997C14.4489 3.74997 14.6397 3.82899 14.7803 3.96964C14.921 4.11029 15 4.30106 15 4.49997V9.74997Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
8
|
+
<path d="M6.75 9L8.25 10.5L11.25 7.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
9
|
+
</svg>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<style scoped>
|
|
13
|
+
|
|
14
|
+
</style>
|
package/lang/en.ts
CHANGED
|
@@ -191,7 +191,7 @@ const EnLocale: RuLocale = {
|
|
|
191
191
|
subtitle: 'Evaluate the volume of competitors\' procurements over a certain period',
|
|
192
192
|
},
|
|
193
193
|
activity: {
|
|
194
|
-
title: '
|
|
194
|
+
title: 'Activity index',
|
|
195
195
|
subtitle: 'Assessment of market risk of current business activity',
|
|
196
196
|
},
|
|
197
197
|
subjects: {
|
|
@@ -202,13 +202,17 @@ const EnLocale: RuLocale = {
|
|
|
202
202
|
title: 'Taxpayer ranking',
|
|
203
203
|
subtitle: 'Taxpayers who regularly pay taxes',
|
|
204
204
|
},
|
|
205
|
+
demography: {
|
|
206
|
+
title: 'Demography',
|
|
207
|
+
subtitle: '',
|
|
208
|
+
}
|
|
205
209
|
},
|
|
206
210
|
},
|
|
207
211
|
fea: {
|
|
208
212
|
label: 'Foreign Economic Activity',
|
|
209
213
|
items: {
|
|
210
214
|
i: {
|
|
211
|
-
t: '
|
|
215
|
+
t: 'Tender search',
|
|
212
216
|
st: 'Information service of foreign trade turnover by foreign economic activity participants',
|
|
213
217
|
},
|
|
214
218
|
o: {
|
|
@@ -224,7 +228,7 @@ const EnLocale: RuLocale = {
|
|
|
224
228
|
st: 'Calculation of Customs Payments. Customs Duties. Customs Fees',
|
|
225
229
|
},
|
|
226
230
|
tr: {
|
|
227
|
-
t: '
|
|
231
|
+
t: 'Market and tariffs',
|
|
228
232
|
st: 'Customs Tariffs and Quotas. Measures for Protecting the Domestic Market. Regulatory Requirements',
|
|
229
233
|
},
|
|
230
234
|
importerMap: {
|
|
@@ -232,7 +236,7 @@ const EnLocale: RuLocale = {
|
|
|
232
236
|
st: '',
|
|
233
237
|
},
|
|
234
238
|
containers: {
|
|
235
|
-
t: '
|
|
239
|
+
t: 'Containers',
|
|
236
240
|
st: '',
|
|
237
241
|
},
|
|
238
242
|
},
|
|
@@ -277,6 +281,27 @@ const EnLocale: RuLocale = {
|
|
|
277
281
|
items: {
|
|
278
282
|
l: {
|
|
279
283
|
t: 'Document Flow',
|
|
284
|
+
st: '',
|
|
285
|
+
},
|
|
286
|
+
docSign: {
|
|
287
|
+
t: 'Document signing',
|
|
288
|
+
st: '',
|
|
289
|
+
},
|
|
290
|
+
docTemplate: {
|
|
291
|
+
t: 'Document templates',
|
|
292
|
+
st: '',
|
|
293
|
+
},
|
|
294
|
+
docRisk: {
|
|
295
|
+
t: 'Document risk check',
|
|
296
|
+
st: '',
|
|
297
|
+
},
|
|
298
|
+
docCompare: {
|
|
299
|
+
t: 'Document comparison',
|
|
300
|
+
st: '',
|
|
301
|
+
},
|
|
302
|
+
docAi: {
|
|
303
|
+
t: 'AI chat for documents',
|
|
304
|
+
st: '',
|
|
280
305
|
},
|
|
281
306
|
},
|
|
282
307
|
},
|
|
@@ -295,6 +320,11 @@ const EnLocale: RuLocale = {
|
|
|
295
320
|
'Automated compliance risk assessment: real-time business protection',
|
|
296
321
|
},
|
|
297
322
|
},
|
|
323
|
+
exportCard: {
|
|
324
|
+
title: 'Data export',
|
|
325
|
+
subTitle: 'Find companies and sole proprietors using the specified filters and receive a list of potential clients',
|
|
326
|
+
receive: 'Get',
|
|
327
|
+
},
|
|
298
328
|
},
|
|
299
329
|
contacts: {
|
|
300
330
|
almaty: {
|
package/lang/kk.ts
CHANGED
|
@@ -191,7 +191,7 @@ const KkLocale: RuLocale = {
|
|
|
191
191
|
subtitle: 'Бәсекелестердің белгілі бір кезеңдегі сатып алу көлемін бағалау',
|
|
192
192
|
},
|
|
193
193
|
activity: {
|
|
194
|
-
title: '
|
|
194
|
+
title: 'Белсенділік индексі',
|
|
195
195
|
subtitle: 'Қазіргі іскерлік белсенділіктің нарықтық тәуекелін бағалау',
|
|
196
196
|
},
|
|
197
197
|
subjects: {
|
|
@@ -202,13 +202,17 @@ const KkLocale: RuLocale = {
|
|
|
202
202
|
title: 'Салық төлеушілер рейтингі',
|
|
203
203
|
subtitle: 'Салықтарды тұрақты түрде төлейтін салық төлеушілер',
|
|
204
204
|
},
|
|
205
|
+
demography: {
|
|
206
|
+
title: 'Демография',
|
|
207
|
+
subtitle: '',
|
|
208
|
+
}
|
|
205
209
|
},
|
|
206
210
|
},
|
|
207
211
|
fea: {
|
|
208
212
|
label: 'СЭҚ',
|
|
209
213
|
items: {
|
|
210
214
|
i: {
|
|
211
|
-
t: '
|
|
215
|
+
t: 'Тендерлерді іздеу',
|
|
212
216
|
st: 'Сыртқы экономикалық қызметке қатысушылардың сыртқы сауда айналымының ақпараттық қызметі',
|
|
213
217
|
},
|
|
214
218
|
o: {
|
|
@@ -224,7 +228,7 @@ const KkLocale: RuLocale = {
|
|
|
224
228
|
st: 'Кедендік төлемдерді есептеу. Кедендік баждар. Кедендік алымдар',
|
|
225
229
|
},
|
|
226
230
|
tr: {
|
|
227
|
-
t: '
|
|
231
|
+
t: 'Нарық және тарифтер',
|
|
228
232
|
st: 'Кедендік тарифтер мен квоталар. Ішкі нарықты қорғау шаралары. Нормативтік талаптар',
|
|
229
233
|
},
|
|
230
234
|
importerMap: {
|
|
@@ -232,7 +236,7 @@ const KkLocale: RuLocale = {
|
|
|
232
236
|
st: '',
|
|
233
237
|
},
|
|
234
238
|
containers: {
|
|
235
|
-
t: '
|
|
239
|
+
t: 'Контейнерлер',
|
|
236
240
|
st: '',
|
|
237
241
|
},
|
|
238
242
|
},
|
|
@@ -277,6 +281,27 @@ const KkLocale: RuLocale = {
|
|
|
277
281
|
items: {
|
|
278
282
|
l: {
|
|
279
283
|
t: 'Құжат айналымы',
|
|
284
|
+
st: '',
|
|
285
|
+
},
|
|
286
|
+
docSign: {
|
|
287
|
+
t: 'Құжаттарға қол қою',
|
|
288
|
+
st: '',
|
|
289
|
+
},
|
|
290
|
+
docTemplate: {
|
|
291
|
+
t: 'Құжат үлгілері',
|
|
292
|
+
st: '',
|
|
293
|
+
},
|
|
294
|
+
docRisk: {
|
|
295
|
+
t: 'Құжатты тәуекелдерге тексеру',
|
|
296
|
+
st: '',
|
|
297
|
+
},
|
|
298
|
+
docCompare: {
|
|
299
|
+
t: 'Құжаттарды салыстыру',
|
|
300
|
+
st: '',
|
|
301
|
+
},
|
|
302
|
+
docAi: {
|
|
303
|
+
t: 'Құжаттар бойынша AI-чат',
|
|
304
|
+
st: '',
|
|
280
305
|
},
|
|
281
306
|
},
|
|
282
307
|
},
|
|
@@ -295,6 +320,11 @@ const KkLocale: RuLocale = {
|
|
|
295
320
|
'Комплаенс тәуекелдерін автоматты түрде тексеру: нақты уақыт режимінде бизнесіңізді қорғаңыз',
|
|
296
321
|
},
|
|
297
322
|
},
|
|
323
|
+
exportCard: {
|
|
324
|
+
title: 'Деректерді жүктеу',
|
|
325
|
+
subTitle: 'Берілген сүзгілер бойынша компаниялар мен ЖК табыңыз және әлеуетті клиенттердің жүктемесін алыңыз',
|
|
326
|
+
receive: 'Алу',
|
|
327
|
+
},
|
|
298
328
|
},
|
|
299
329
|
contacts: {
|
|
300
330
|
almaty: {
|
package/lang/ru.ts
CHANGED
|
@@ -190,12 +190,12 @@ const RuLocale = {
|
|
|
190
190
|
'Оцените объем закупок конкурентов за определенный период',
|
|
191
191
|
},
|
|
192
192
|
activity: {
|
|
193
|
-
title: 'Индекс
|
|
193
|
+
title: 'Индекс активности',
|
|
194
194
|
subtitle:
|
|
195
195
|
'Оценка рыночного риска текущей деловой активности',
|
|
196
196
|
},
|
|
197
197
|
subjects: {
|
|
198
|
-
title: '
|
|
198
|
+
title: 'Субъекты бизнеса',
|
|
199
199
|
subtitle:
|
|
200
200
|
'Изменение числа бизнес-субъектов в отраслях и секторах экономики',
|
|
201
201
|
},
|
|
@@ -203,13 +203,17 @@ const RuLocale = {
|
|
|
203
203
|
title: 'Рейтинг налогоплательщиков',
|
|
204
204
|
subtitle: 'Налогоплательщики, регулярно уплачивающие налоги',
|
|
205
205
|
},
|
|
206
|
+
demography: {
|
|
207
|
+
title: 'Демография',
|
|
208
|
+
subtitle: '',
|
|
209
|
+
}
|
|
206
210
|
},
|
|
207
211
|
},
|
|
208
212
|
fea: {
|
|
209
213
|
label: 'ВЭД',
|
|
210
214
|
items: {
|
|
211
215
|
i: {
|
|
212
|
-
t: '
|
|
216
|
+
t: 'Поиск тендеров',
|
|
213
217
|
st: 'Информационный сервис внешнеторгового оборота в разрезе участников ВЭД',
|
|
214
218
|
},
|
|
215
219
|
o: {
|
|
@@ -225,15 +229,15 @@ const RuLocale = {
|
|
|
225
229
|
st: 'Расчет таможенных платежей. Таможенные пошлины. Таможенные сборы',
|
|
226
230
|
},
|
|
227
231
|
tr: {
|
|
228
|
-
t: '
|
|
232
|
+
t: 'Рынок и тарифы',
|
|
229
233
|
st: 'Таможенные тарифы и квоты. Меры защиты внутреннего рынка. Нормативные требования',
|
|
230
234
|
},
|
|
231
235
|
importerMap: {
|
|
232
|
-
t: 'Карта
|
|
236
|
+
t: 'Карта импортёра',
|
|
233
237
|
st: '',
|
|
234
238
|
},
|
|
235
239
|
containers: {
|
|
236
|
-
t: '
|
|
240
|
+
t: 'Контейнеры',
|
|
237
241
|
st: '',
|
|
238
242
|
},
|
|
239
243
|
},
|
|
@@ -278,6 +282,27 @@ const RuLocale = {
|
|
|
278
282
|
items: {
|
|
279
283
|
l: {
|
|
280
284
|
t: 'Документооборот',
|
|
285
|
+
st: '',
|
|
286
|
+
},
|
|
287
|
+
docSign: {
|
|
288
|
+
t: 'Подписание документов',
|
|
289
|
+
st: '',
|
|
290
|
+
},
|
|
291
|
+
docTemplate: {
|
|
292
|
+
t: 'Шаблоны документов',
|
|
293
|
+
st: '',
|
|
294
|
+
},
|
|
295
|
+
docRisk: {
|
|
296
|
+
t: 'Проверка документа на риски',
|
|
297
|
+
st: '',
|
|
298
|
+
},
|
|
299
|
+
docCompare: {
|
|
300
|
+
t: 'Сравнение документов',
|
|
301
|
+
st: '',
|
|
302
|
+
},
|
|
303
|
+
docAi: {
|
|
304
|
+
t: 'AI-чат по документам',
|
|
305
|
+
st: '',
|
|
281
306
|
},
|
|
282
307
|
},
|
|
283
308
|
},
|
|
@@ -295,6 +320,11 @@ const RuLocale = {
|
|
|
295
320
|
subtitle: 'Автопроверка комплаенс-рисков: защита бизнеса в режиме реального времени',
|
|
296
321
|
},
|
|
297
322
|
},
|
|
323
|
+
exportCard: {
|
|
324
|
+
title: 'Выгрузка данных',
|
|
325
|
+
subTitle: 'Найдите компании и ИП по заданным фильтрам и получите выгрузку потенциальных клиентов',
|
|
326
|
+
receive: 'Получить',
|
|
327
|
+
},
|
|
298
328
|
},
|
|
299
329
|
contacts: {
|
|
300
330
|
almaty: {
|
package/package.json
CHANGED
package/shared/constans/pages.ts
CHANGED
|
@@ -62,7 +62,8 @@ export const PAGES = {
|
|
|
62
62
|
analysis: '/purchasing-analysis',
|
|
63
63
|
index: '/business-activity',
|
|
64
64
|
rating: '/tax-payment',
|
|
65
|
-
business: '/business-entities'
|
|
65
|
+
business: '/business-entities',
|
|
66
|
+
demography: '/demography',
|
|
66
67
|
},
|
|
67
68
|
fea: {
|
|
68
69
|
main: '/',
|
|
@@ -85,6 +86,11 @@ export const PAGES = {
|
|
|
85
86
|
sb: '/sb'
|
|
86
87
|
},
|
|
87
88
|
edo: {
|
|
88
|
-
l: '/'
|
|
89
|
+
l: '/',
|
|
90
|
+
docSign: '/create?step=2&source=upload',
|
|
91
|
+
docTemplate: '/create?step=2&source=template',
|
|
92
|
+
docRisk: '/create?step=2&source=import&postImportAction=risks',
|
|
93
|
+
docCompare: '/create?step=2&source=import',
|
|
94
|
+
docAi: '/create?step=3&source=blank',
|
|
89
95
|
}
|
|
90
96
|
}
|