@finema/finework-layer 2.0.51 → 2.0.52
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/CHANGELOG.md +6 -0
- package/app/components/Layout/Apps.vue +3 -1
- package/app/components/Notifications/index.vue +51 -24
- package/app/components/PortalApp.vue +258 -573
- package/app/composables/useAuth.ts +41 -22
- package/app/constants/routes.ts +8 -0
- package/package.json +1 -1
- package/public/admin/asset.svg +20 -0
- package/public/admin/clock-in-admin-logo.svg +33 -0
- package/public/admin/clock-in-logo.svg +27 -0
- package/public/admin/contract.svg +41 -0
- package/public/admin/cost-sheet.svg +19 -0
- package/public/admin/document.svg +29 -0
- package/public/admin/efactoring.svg +23 -0
- package/public/admin/employee.svg +16 -0
- package/public/admin/evaluation.svg +29 -0
- package/public/admin/finesign.png +0 -0
- package/public/admin/guarantee.svg +25 -0
- package/public/admin/loan.svg +35 -0
- package/public/admin/newsletter.svg +23 -0
- package/public/admin/pmo-logo.svg +28 -0
- package/public/admin/pmo_delivery.svg +21 -0
- package/public/admin/pmo_presale_bidding.svg +30 -0
- package/public/admin/pmo_setup.svg +18 -0
- package/public/admin/pmo_warranty.svg +26 -0
- package/public/admin/purchase.svg +22 -0
- package/public/admin/quotation.svg +21 -0
- package/public/admin/recruit.svg +21 -0
- package/public/admin/report.svg +41 -0
- package/public/admin/request-admin.svg +44 -0
- package/public/admin/request.svg +42 -0
- package/public/admin/resource-allocation.svg +26 -0
- package/public/admin/resource.svg +22 -0
- package/public/admin/spider-web.png +0 -0
- package/public/admin/super-admin-logo.svg +22 -0
- package/public/admin/support.svg +19 -0
- package/public/admin/timesheet-admin-logo.svg +87 -0
- package/public/admin/timesheet-logo.svg +85 -0
- package/public/admin/todo.svg +21 -0
- package/public/admin/tor.svg +43 -0
|
@@ -1,284 +1,126 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
:key="app.name"
|
|
19
|
-
:to="app.status !== StatusPortal.DEVELOPING ? app.to : undefined"
|
|
20
|
-
class="relative flex items-center gap-3 rounded-lg px-2.5 py-[15px]"
|
|
21
|
-
:class="app.status === StatusPortal.DEVELOPING
|
|
22
|
-
? 'cursor-not-allowed bg-gray-200 opacity-60'
|
|
23
|
-
: 'bg-gray-100 hover:bg-gray-200'"
|
|
24
|
-
@click="app.status !== StatusPortal.DEVELOPING && handleLinkClick(app.to)"
|
|
25
|
-
>
|
|
26
|
-
<div
|
|
27
|
-
v-if="app.status === StatusPortal.DEVELOPING"
|
|
28
|
-
class="absolute top-2 right-2 rounded-full bg-orange-100 px-2 py-0.5 text-xs font-semibold text-orange-600"
|
|
29
|
-
>
|
|
30
|
-
กำลังพัฒนา
|
|
31
|
-
</div>
|
|
32
|
-
<img
|
|
33
|
-
:src="app.logo"
|
|
34
|
-
:alt="app.label"
|
|
35
|
-
class="h-[45px] w-[45px] bg-white"
|
|
36
|
-
/>
|
|
37
|
-
<div>
|
|
38
|
-
<div class="text-lg font-bold">
|
|
39
|
-
{{ app.label }}
|
|
40
|
-
</div>
|
|
41
|
-
<div class="text-sm text-gray-500">
|
|
42
|
-
{{ app.description }}
|
|
43
|
-
</div>
|
|
44
|
-
</div>
|
|
45
|
-
</component>
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
48
|
-
<div
|
|
49
|
-
v-if="managementApps.length > 0"
|
|
50
|
-
class="space-y-5"
|
|
51
|
-
>
|
|
52
|
-
<div class="text-lg font-bold text-gray-600">
|
|
53
|
-
Management
|
|
54
|
-
</div>
|
|
55
|
-
<div
|
|
56
|
-
class="grid"
|
|
57
|
-
:class="[isNavbar ?`gap-5 md:grid-cols-2 xl:grid-cols-4` : `grid-cols-1 gap-2`]"
|
|
58
|
-
>
|
|
59
|
-
<component
|
|
60
|
-
:is="app.status === StatusPortal.DEVELOPING ? 'div' : NuxtLink"
|
|
61
|
-
v-for="app in managementApps"
|
|
62
|
-
:key="app.name"
|
|
63
|
-
:to="app.status !== StatusPortal.DEVELOPING ? app.to : undefined"
|
|
64
|
-
class="relative flex items-center gap-3 rounded-lg px-2.5 py-[15px]"
|
|
65
|
-
:class="app.status === StatusPortal.DEVELOPING
|
|
66
|
-
? 'cursor-not-allowed bg-gray-200 opacity-60'
|
|
67
|
-
: 'bg-gray-100 hover:bg-gray-200'"
|
|
68
|
-
@click="app.status !== StatusPortal.DEVELOPING && handleLinkClick(app.to)"
|
|
69
|
-
>
|
|
70
|
-
<div
|
|
71
|
-
v-if="app.status === StatusPortal.DEVELOPING"
|
|
72
|
-
class="absolute top-2 right-2 rounded-full bg-orange-100 px-2 py-0.5 text-xs font-semibold text-orange-600"
|
|
73
|
-
>
|
|
74
|
-
กำลังพัฒนา
|
|
75
|
-
</div>
|
|
76
|
-
<img
|
|
77
|
-
:src="app.logo"
|
|
78
|
-
:alt="app.label"
|
|
79
|
-
class="h-[45px] w-[45px] bg-white"
|
|
80
|
-
/>
|
|
81
|
-
<div>
|
|
82
|
-
<div class="text-lg font-bold">
|
|
83
|
-
{{ app.label }}
|
|
84
|
-
</div>
|
|
85
|
-
<div class="text-sm text-gray-500">
|
|
86
|
-
{{ app.description }}
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
89
|
-
</component>
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
2
|
+
<Card
|
|
3
|
+
v-if="categories.length > 0"
|
|
4
|
+
:ui="{
|
|
5
|
+
body: isNavbar
|
|
6
|
+
? 'md:max-h-[calc(100vh-115px)] overflow-auto'
|
|
7
|
+
: 'h-full overflow-auto p-4!',
|
|
8
|
+
}"
|
|
9
|
+
>
|
|
10
|
+
<div class="space-y-6 bg-white">
|
|
11
|
+
<Input
|
|
12
|
+
v-model="search"
|
|
13
|
+
icon="ph:magnifying-glass"
|
|
14
|
+
placeholder="Search app"
|
|
15
|
+
size="lg"
|
|
16
|
+
:ui="{ base: 'rounded-lg' }"
|
|
17
|
+
/>
|
|
92
18
|
|
|
93
19
|
<div
|
|
94
|
-
v-
|
|
95
|
-
|
|
20
|
+
v-for="category in filteredCategories"
|
|
21
|
+
:key="category.key"
|
|
22
|
+
class="space-y-3"
|
|
96
23
|
>
|
|
97
|
-
<div class="text-
|
|
98
|
-
|
|
24
|
+
<div class="text-base font-bold">
|
|
25
|
+
{{ category.title }}
|
|
99
26
|
</div>
|
|
100
|
-
<div
|
|
101
|
-
class="grid"
|
|
102
|
-
:class="[isNavbar ?`gap-5 md:grid-cols-2 xl:grid-cols-4` : `grid-cols-1 gap-2`]"
|
|
103
|
-
>
|
|
104
|
-
<component
|
|
105
|
-
:is="app.status === StatusPortal.DEVELOPING ? 'div' : NuxtLink"
|
|
106
|
-
v-for="app in financeApps"
|
|
107
|
-
:key="app.name"
|
|
108
|
-
:to="app.status !== StatusPortal.DEVELOPING ? app.to : undefined"
|
|
109
|
-
class="relative flex items-center gap-3 rounded-lg px-2.5 py-[15px]"
|
|
110
|
-
:class="app.status === StatusPortal.DEVELOPING
|
|
111
|
-
? 'cursor-not-allowed bg-gray-200 opacity-60'
|
|
112
|
-
: 'bg-gray-100 hover:bg-gray-200'"
|
|
113
|
-
@click="app.status !== StatusPortal.DEVELOPING && handleLinkClick(app.to)"
|
|
114
|
-
>
|
|
115
|
-
<div
|
|
116
|
-
v-if="app.status === StatusPortal.DEVELOPING"
|
|
117
|
-
class="absolute top-2 right-2 rounded-full bg-orange-100 px-2 py-0.5 text-xs font-semibold text-orange-600"
|
|
118
|
-
>
|
|
119
|
-
กำลังพัฒนา
|
|
120
|
-
</div>
|
|
121
27
|
|
|
122
|
-
|
|
123
|
-
:src="app.logo"
|
|
124
|
-
:alt="app.label"
|
|
125
|
-
class="h-[45px] w-[45px] bg-white"
|
|
126
|
-
/>
|
|
127
|
-
|
|
128
|
-
<div>
|
|
129
|
-
<div class="text-lg font-bold">
|
|
130
|
-
{{ app.label }}
|
|
131
|
-
</div>
|
|
132
|
-
<div class="text-sm text-gray-500">
|
|
133
|
-
{{ app.description }}
|
|
134
|
-
</div>
|
|
135
|
-
</div>
|
|
136
|
-
</component>
|
|
137
|
-
</div>
|
|
138
|
-
</div>
|
|
139
|
-
|
|
140
|
-
<div
|
|
141
|
-
v-if="peopleApps.length >0"
|
|
142
|
-
class="space-y-5"
|
|
143
|
-
>
|
|
144
|
-
<div class="text-lg font-bold text-gray-600">
|
|
145
|
-
People
|
|
146
|
-
</div>
|
|
28
|
+
<!-- Navbar: compact icon-on-top grid -->
|
|
147
29
|
<div
|
|
148
|
-
|
|
149
|
-
|
|
30
|
+
v-if="isNavbar"
|
|
31
|
+
class="grid gap-x-2 gap-y-4"
|
|
32
|
+
:class="gridColsClass"
|
|
150
33
|
>
|
|
151
34
|
<component
|
|
152
|
-
:is="app
|
|
153
|
-
v-for="app in
|
|
35
|
+
:is="linkComponent(app)"
|
|
36
|
+
v-for="app in category.apps"
|
|
154
37
|
:key="app.name"
|
|
155
|
-
:to="app
|
|
156
|
-
class="
|
|
157
|
-
:class="app
|
|
158
|
-
|
|
159
|
-
: 'bg-gray-100 hover:bg-gray-200'"
|
|
160
|
-
@click="app.status !== StatusPortal.DEVELOPING && handleLinkClick(app.to)"
|
|
38
|
+
:to="linkTo(app)"
|
|
39
|
+
class="group flex flex-col items-center gap-2 rounded-xl p-2 text-center transition-colors"
|
|
40
|
+
:class="isDeveloping(app) ? 'cursor-not-allowed opacity-60' : 'hover:bg-gray-100'"
|
|
41
|
+
@click="onAppClick(app)"
|
|
161
42
|
>
|
|
162
|
-
<div
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
<div class="text-lg font-bold">
|
|
175
|
-
{{ app.label }}
|
|
176
|
-
</div>
|
|
177
|
-
<div class="text-sm text-gray-500">
|
|
178
|
-
{{ app.description }}
|
|
179
|
-
</div>
|
|
43
|
+
<div class="relative">
|
|
44
|
+
<img
|
|
45
|
+
:src="app.logo"
|
|
46
|
+
:alt="app.label"
|
|
47
|
+
class="size-12.5 rounded-xl object-contain"
|
|
48
|
+
/>
|
|
49
|
+
<span
|
|
50
|
+
v-if="isDeveloping(app)"
|
|
51
|
+
class="absolute -top-1.5 -right-1.5 rounded-full bg-orange-100 px-1.5 py-0.5 text-[10px] font-semibold text-orange-600"
|
|
52
|
+
>
|
|
53
|
+
กำลังพัฒนา
|
|
54
|
+
</span>
|
|
180
55
|
</div>
|
|
56
|
+
<span class="line-clamp-2 text-sm font-semibold">
|
|
57
|
+
{{ app.label }}
|
|
58
|
+
</span>
|
|
181
59
|
</component>
|
|
182
60
|
</div>
|
|
183
|
-
</div>
|
|
184
61
|
|
|
185
|
-
|
|
186
|
-
v-if="legalApps.length > 0"
|
|
187
|
-
class="space-y-5"
|
|
188
|
-
>
|
|
189
|
-
<div class="text-lg font-bold text-gray-600">
|
|
190
|
-
Legal
|
|
191
|
-
</div>
|
|
62
|
+
<!-- Standalone: long list with descriptions -->
|
|
192
63
|
<div
|
|
193
|
-
|
|
194
|
-
|
|
64
|
+
v-else
|
|
65
|
+
class="flex flex-col"
|
|
195
66
|
>
|
|
196
67
|
<component
|
|
197
|
-
:is="app
|
|
198
|
-
v-for="app in
|
|
68
|
+
:is="linkComponent(app)"
|
|
69
|
+
v-for="app in category.apps"
|
|
199
70
|
:key="app.name"
|
|
200
|
-
:to="app
|
|
201
|
-
class="
|
|
202
|
-
:class="app
|
|
203
|
-
|
|
204
|
-
: 'bg-gray-100 hover:bg-gray-200'"
|
|
205
|
-
@click="app.status !== StatusPortal.DEVELOPING && handleLinkClick(app.to)"
|
|
71
|
+
:to="linkTo(app)"
|
|
72
|
+
class="flex items-start gap-3 border-b border-gray-100 px-1 py-3 transition-colors last:border-0"
|
|
73
|
+
:class="isDeveloping(app) ? 'cursor-not-allowed opacity-60' : 'hover:bg-gray-50'"
|
|
74
|
+
@click="onAppClick(app)"
|
|
206
75
|
>
|
|
207
|
-
<div
|
|
208
|
-
v-if="app.status === StatusPortal.DEVELOPING"
|
|
209
|
-
class="absolute top-2 right-2 rounded-full bg-orange-100 px-2 py-0.5 text-xs font-semibold text-orange-600"
|
|
210
|
-
>
|
|
211
|
-
กำลังพัฒนา
|
|
212
|
-
</div>
|
|
213
76
|
<img
|
|
214
77
|
:src="app.logo"
|
|
215
78
|
:alt="app.label"
|
|
216
|
-
class="
|
|
79
|
+
class="size-11 shrink-0 object-contain"
|
|
217
80
|
/>
|
|
218
|
-
<div>
|
|
219
|
-
<div class="
|
|
81
|
+
<div class="min-w-0">
|
|
82
|
+
<div class="flex items-center gap-2 font-bold text-gray-900">
|
|
220
83
|
{{ app.label }}
|
|
84
|
+
<span
|
|
85
|
+
v-if="isDeveloping(app)"
|
|
86
|
+
class="rounded-full bg-orange-100 px-1.5 py-0.5 text-[10px] font-semibold text-orange-600"
|
|
87
|
+
>
|
|
88
|
+
กำลังพัฒนา
|
|
89
|
+
</span>
|
|
221
90
|
</div>
|
|
222
|
-
<div class="text-sm text-gray-500">
|
|
91
|
+
<div class="line-clamp-2 text-sm text-gray-500">
|
|
223
92
|
{{ app.description }}
|
|
224
93
|
</div>
|
|
225
94
|
</div>
|
|
226
95
|
</component>
|
|
227
96
|
</div>
|
|
228
97
|
</div>
|
|
229
|
-
</div>
|
|
230
|
-
</DefineTemplate>
|
|
231
|
-
<Card
|
|
232
|
-
v-if="dailyApps.length > 0 || managementApps.length > 0 || financeApps.length > 0 || peopleApps.length > 0 || legalApps.length > 0"
|
|
233
|
-
:ui="{
|
|
234
|
-
body: isNavbar
|
|
235
|
-
? 'md:max-h-[100vh] md:max-h-[calc(100vh-115px)] overflow-auto'
|
|
236
|
-
: 'h-full overflow-auto p-4!',
|
|
237
|
-
}"
|
|
238
|
-
>
|
|
239
|
-
<div class="bg-white">
|
|
240
|
-
<ReuseTemplate v-if="isNavbar" />
|
|
241
|
-
<Collapsible
|
|
242
|
-
v-else
|
|
243
|
-
v-model:open="open"
|
|
244
|
-
default-open
|
|
245
|
-
>
|
|
246
|
-
<div class="flex items-center justify-between gap-4">
|
|
247
|
-
<div class="mb-5 flex items-center gap-2">
|
|
248
|
-
<img
|
|
249
|
-
src="/icon-finema.png"
|
|
250
|
-
alt="icon-finema"
|
|
251
|
-
class="h-8 w-8 -translate-y-1"
|
|
252
|
-
/>
|
|
253
|
-
<div class="text-2xl font-bold">
|
|
254
|
-
My Apps
|
|
255
|
-
</div>
|
|
256
|
-
</div>
|
|
257
98
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
/>
|
|
264
|
-
</div>
|
|
265
|
-
<template #content>
|
|
266
|
-
<ReuseTemplate />
|
|
267
|
-
</template>
|
|
268
|
-
</Collapsible>
|
|
99
|
+
<Empty
|
|
100
|
+
v-if="search && filteredCategories.length === 0"
|
|
101
|
+
icon="ph:magnifying-glass"
|
|
102
|
+
message="No apps found"
|
|
103
|
+
/>
|
|
269
104
|
</div>
|
|
270
105
|
</Card>
|
|
271
106
|
</template>
|
|
272
107
|
|
|
273
108
|
<script lang="ts" setup>
|
|
274
109
|
import { resolveComponent } from 'vue'
|
|
275
|
-
|
|
110
|
+
// Import the shared maps straight from the layer so PortalApp stays deterministic
|
|
111
|
+
// even in apps that shadow UserModuleLabel / UserModuleLogo with their own copy.
|
|
112
|
+
import {
|
|
113
|
+
UserModuleAdminLabel,
|
|
114
|
+
UserModuleAdminLogo,
|
|
115
|
+
UserModuleLabel,
|
|
116
|
+
UserModuleLogo,
|
|
117
|
+
} from '#layer/app/composables/useAuth'
|
|
276
118
|
|
|
277
119
|
const emit = defineEmits<{
|
|
278
120
|
(e: 'close'): void
|
|
279
121
|
}>()
|
|
280
122
|
|
|
281
|
-
|
|
123
|
+
defineProps<{
|
|
282
124
|
isNavbar?: boolean
|
|
283
125
|
}>()
|
|
284
126
|
|
|
@@ -286,11 +128,26 @@ const enum StatusPortal {
|
|
|
286
128
|
ACTIVE = 'active',
|
|
287
129
|
DEVELOPING = 'developing',
|
|
288
130
|
}
|
|
131
|
+
|
|
132
|
+
interface IPortalApp {
|
|
133
|
+
name: string
|
|
134
|
+
label: string
|
|
135
|
+
logo: string
|
|
136
|
+
description: string
|
|
137
|
+
to: string
|
|
138
|
+
status: StatusPortal
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
interface IPortalCategory {
|
|
142
|
+
key: string
|
|
143
|
+
title: string
|
|
144
|
+
apps: IPortalApp[]
|
|
145
|
+
}
|
|
146
|
+
|
|
289
147
|
const NuxtLink = resolveComponent('NuxtLink')
|
|
290
148
|
const auth = useAuth()
|
|
291
149
|
const route = useRoute()
|
|
292
|
-
const
|
|
293
|
-
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
|
|
150
|
+
const search = ref('')
|
|
294
151
|
|
|
295
152
|
const handleLinkClick = (to: string) => {
|
|
296
153
|
if (route.path === to) {
|
|
@@ -298,372 +155,200 @@ const handleLinkClick = (to: string) => {
|
|
|
298
155
|
}
|
|
299
156
|
}
|
|
300
157
|
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
158
|
+
const isDeveloping = (app: IPortalApp) => app.status === StatusPortal.DEVELOPING
|
|
159
|
+
const linkComponent = (app: IPortalApp) => (isDeveloping(app) ? 'div' : NuxtLink)
|
|
160
|
+
const linkTo = (app: IPortalApp) => (isDeveloping(app) ? undefined : app.to)
|
|
161
|
+
|
|
162
|
+
const onAppClick = (app: IPortalApp) => {
|
|
163
|
+
if (!isDeveloping(app)) {
|
|
164
|
+
handleLinkClick(app.to)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const USER_ADMIN_SUPER = [Permission.USER, Permission.ADMIN, Permission.SUPER]
|
|
169
|
+
const ADMIN_SUPER = [Permission.ADMIN, Permission.SUPER]
|
|
170
|
+
|
|
171
|
+
const can = (module: UserModule, ...permissions: AccessPermission[]) =>
|
|
172
|
+
auth.hasPermission(module, ...permissions)
|
|
173
|
+
|
|
174
|
+
/** App whose label/logo come from the shared UserModule maps. */
|
|
175
|
+
const toApp = (
|
|
176
|
+
module: UserModule,
|
|
177
|
+
to: string,
|
|
178
|
+
description: string,
|
|
179
|
+
overrides: Partial<IPortalApp> = {},
|
|
180
|
+
): IPortalApp => ({
|
|
181
|
+
name: overrides.name ?? module,
|
|
182
|
+
label: overrides.label ?? UserModuleLabel[module as keyof typeof UserModuleLabel],
|
|
183
|
+
logo: overrides.logo ?? UserModuleLogo[module as keyof typeof UserModuleLogo],
|
|
184
|
+
description,
|
|
185
|
+
to,
|
|
186
|
+
status: overrides.status ?? StatusPortal.ACTIVE,
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
/** Admin-console variant of a module, using the shared admin maps. */
|
|
190
|
+
const toAdminApp = (
|
|
191
|
+
module: keyof typeof UserModuleAdminLabel,
|
|
192
|
+
to: string,
|
|
193
|
+
description: string,
|
|
194
|
+
): IPortalApp => ({
|
|
195
|
+
name: `${module}-admin`,
|
|
196
|
+
label: UserModuleAdminLabel[module],
|
|
197
|
+
logo: UserModuleAdminLogo[module],
|
|
198
|
+
description,
|
|
199
|
+
to,
|
|
200
|
+
status: StatusPortal.ACTIVE,
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
const dailyApps = computed<IPortalApp[]>(() => [
|
|
204
|
+
...(can(UserModule.CHECKIN, ...USER_ADMIN_SUPER)
|
|
205
|
+
? [toApp(UserModule.CHECKIN, routes.clockin.home.to, 'เช็กอินเวลางาน และเลือกสถานที่ทำงาน')]
|
|
313
206
|
: []),
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
name: 'todo',
|
|
324
|
-
logo: '/admin/todo.png',
|
|
325
|
-
label: 'Todo',
|
|
326
|
-
description: 'ระบบจัดการงาน',
|
|
327
|
-
to: routes.todo.dashboard.to,
|
|
328
|
-
status: StatusPortal.ACTIVE,
|
|
329
|
-
},
|
|
330
|
-
{
|
|
331
|
-
name: 'Request',
|
|
332
|
-
logo: '/admin/request.png',
|
|
333
|
-
label: 'Request',
|
|
334
|
-
description: 'ระบบขอ ลา เบิก อนุมัติรายการต่างๆ',
|
|
335
|
-
to: routes.request.myRequest.requests.to,
|
|
336
|
-
status: StatusPortal.ACTIVE,
|
|
337
|
-
},
|
|
207
|
+
toApp(UserModule.TIMESHEET, routes.timesheet.home.to, 'บันทึกงานที่ทำในแต่ละวัน'),
|
|
208
|
+
toApp(UserModule.TODO, routes.todo.dashboard.to, 'ระบบจัดการงาน'),
|
|
209
|
+
toApp(UserModule.REQUEST, routes.request.myRequest.requests.to, 'ระบบขอ ลา เบิก อนุมัติรายการต่างๆ'),
|
|
210
|
+
...(can(UserModule.CHECKIN, ...USER_ADMIN_SUPER)
|
|
211
|
+
? [toApp(UserModule.CHECKIN, routes.clockin.home.to, 'เช็กอินเวลางาน และเลือกสถานที่ทำงาน')]
|
|
212
|
+
: []),
|
|
213
|
+
toApp(UserModule.TIMESHEET, routes.timesheet.home.to, 'บันทึกงานที่ทำในแต่ละวัน'),
|
|
214
|
+
toApp(UserModule.TODO, routes.todo.dashboard.to, 'ระบบจัดการงาน'),
|
|
215
|
+
toApp(UserModule.REQUEST, routes.request.myRequest.requests.to, 'ระบบขอ ลา เบิก อนุมัติรายการต่างๆ'),
|
|
338
216
|
])
|
|
339
217
|
|
|
340
|
-
const managementApps = computed(() => [
|
|
341
|
-
...(
|
|
342
|
-
UserModule.PMO,
|
|
343
|
-
Permission.ADMIN,
|
|
344
|
-
Permission.USER,
|
|
345
|
-
Permission.SUPER,
|
|
346
|
-
)
|
|
347
|
-
? [
|
|
348
|
-
{
|
|
349
|
-
name: 'pmo',
|
|
350
|
-
logo: '/admin/pmo-logo.png',
|
|
351
|
-
label: 'PMO',
|
|
352
|
-
description: 'จัดระเบียบและบริหารโครงการของคุณ',
|
|
353
|
-
to: routes.pmo.project.projects.to,
|
|
354
|
-
status: StatusPortal.ACTIVE,
|
|
355
|
-
},
|
|
356
|
-
]
|
|
218
|
+
const managementApps = computed<IPortalApp[]>(() => [
|
|
219
|
+
...(can(UserModule.PMO, ...USER_ADMIN_SUPER)
|
|
220
|
+
? [toApp(UserModule.PMO, routes.pmo.project.projects.to, 'จัดระเบียบและบริหารโครงการของคุณ')]
|
|
357
221
|
: []),
|
|
358
|
-
...(
|
|
359
|
-
UserModule.PMO_SETUP,
|
|
360
|
-
Permission.ADMIN,
|
|
361
|
-
Permission.USER,
|
|
362
|
-
Permission.SUPER,
|
|
363
|
-
)
|
|
364
|
-
? [
|
|
365
|
-
{
|
|
366
|
-
name: 'pmo-setup',
|
|
367
|
-
logo: '/admin/pmo_setup.png',
|
|
368
|
-
label: 'Lead in',
|
|
369
|
-
description: 'ตั้งค่าและบริหารจัดการโครงการ PMO',
|
|
370
|
-
to: routes.pmoSetup.dashboard.to,
|
|
371
|
-
status: StatusPortal.ACTIVE,
|
|
372
|
-
},
|
|
373
|
-
]
|
|
222
|
+
...(can(UserModule.PMO_SETUP, ...USER_ADMIN_SUPER)
|
|
223
|
+
? [toApp(UserModule.PMO_SETUP, routes.pmoSetup.dashboard.to, 'ตั้งค่าและบริหารจัดการโครงการ PMO')]
|
|
374
224
|
: []),
|
|
375
|
-
...(
|
|
376
|
-
UserModule.PMO_PRESALE_BIDDING,
|
|
377
|
-
Permission.ADMIN,
|
|
378
|
-
Permission.USER,
|
|
379
|
-
Permission.SUPER,
|
|
380
|
-
)
|
|
381
|
-
? [
|
|
382
|
-
{
|
|
383
|
-
name: 'pmo-presale-bidding',
|
|
384
|
-
logo: '/admin/pmo_presale_bidding.png',
|
|
385
|
-
label: 'Presale & Bidding',
|
|
386
|
-
description: 'บริหารจัดการงาน Presale และ Bidding',
|
|
387
|
-
to: routes.pmoPresaleBidding.dashboard.to,
|
|
388
|
-
status: StatusPortal.ACTIVE,
|
|
389
|
-
},
|
|
390
|
-
]
|
|
225
|
+
...(can(UserModule.PMO_PRESALE_BIDDING, ...USER_ADMIN_SUPER)
|
|
226
|
+
? [toApp(UserModule.PMO_PRESALE_BIDDING, routes.pmoPresaleBidding.dashboard.to, 'บริหารจัดการงาน Presale และ Bidding')]
|
|
391
227
|
: []),
|
|
392
|
-
...(
|
|
393
|
-
UserModule.PMO_DELIVERY,
|
|
394
|
-
Permission.ADMIN,
|
|
395
|
-
Permission.USER,
|
|
396
|
-
Permission.SUPER,
|
|
397
|
-
)
|
|
398
|
-
? [
|
|
399
|
-
{
|
|
400
|
-
name: 'pmo-delivery',
|
|
401
|
-
logo: '/admin/pmo_delivery.png',
|
|
402
|
-
label: 'Delivery',
|
|
403
|
-
description: 'บริหารจัดการโครงการช่วง Delivery',
|
|
404
|
-
to: routes.pmoDelivery.dashboard.to,
|
|
405
|
-
status: StatusPortal.ACTIVE,
|
|
406
|
-
},
|
|
407
|
-
]
|
|
228
|
+
...(can(UserModule.PMO_DELIVERY, ...USER_ADMIN_SUPER)
|
|
229
|
+
? [toApp(UserModule.PMO_DELIVERY, routes.pmoDelivery.dashboard.to, 'บริหารจัดการโครงการช่วง Delivery')]
|
|
408
230
|
: []),
|
|
409
|
-
...(
|
|
410
|
-
UserModule.PMO_WARRANTY,
|
|
411
|
-
Permission.ADMIN,
|
|
412
|
-
Permission.USER,
|
|
413
|
-
Permission.SUPER,
|
|
414
|
-
)
|
|
415
|
-
? [
|
|
416
|
-
{
|
|
417
|
-
name: 'pmo-warranty',
|
|
418
|
-
logo: '/admin/pmo_warranty.png',
|
|
419
|
-
label: 'Warranty',
|
|
420
|
-
description: 'บริหารจัดการโครงการช่วง Warranty',
|
|
421
|
-
to: routes.pmoWarranty.dashboard.to,
|
|
422
|
-
status: StatusPortal.ACTIVE,
|
|
423
|
-
},
|
|
424
|
-
]
|
|
231
|
+
...(can(UserModule.PMO_WARRANTY, ...USER_ADMIN_SUPER)
|
|
232
|
+
? [toApp(UserModule.PMO_WARRANTY, routes.pmoWarranty.dashboard.to, 'บริหารจัดการโครงการช่วง Warranty')]
|
|
425
233
|
: []),
|
|
426
|
-
...(
|
|
427
|
-
? [
|
|
428
|
-
{
|
|
429
|
-
name: 'clockin-admin',
|
|
430
|
-
logo: '/admin/clock-in-admin-logo.png',
|
|
431
|
-
label: 'Clock-in Report',
|
|
432
|
-
description: 'รายงานการลงเวลา',
|
|
433
|
-
to: routes.adminClockin.checkinDashboard.to,
|
|
434
|
-
status: StatusPortal.ACTIVE,
|
|
435
|
-
},
|
|
436
|
-
]
|
|
234
|
+
...(can(UserModule.RESOURCE_ALLOCATION, ...ADMIN_SUPER)
|
|
235
|
+
? [toApp(UserModule.RESOURCE_ALLOCATION, routes.resourceAllocation.dashboard.to, 'วางแผนและจัดสรรกำลังคนในโครงการ')]
|
|
437
236
|
: []),
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
? [
|
|
441
|
-
{
|
|
442
|
-
name: 'timesheet-admin',
|
|
443
|
-
logo: '/admin/timesheet-admin-logo.png',
|
|
444
|
-
label: 'Timesheet Report',
|
|
445
|
-
description: 'รายงานการบันทึกข้อมูลไทม์ชีท',
|
|
446
|
-
to: routes.adminTimesheet.summaryReport.to,
|
|
447
|
-
status: StatusPortal.ACTIVE,
|
|
448
|
-
},
|
|
449
|
-
]
|
|
237
|
+
...(can(UserModule.CHECKIN, ...ADMIN_SUPER)
|
|
238
|
+
? [toAdminApp(UserModule.CHECKIN, routes.adminClockin.checkinDashboard.to, 'รายงานการลงเวลา')]
|
|
450
239
|
: []),
|
|
451
|
-
...(
|
|
452
|
-
? [
|
|
453
|
-
{
|
|
454
|
-
name: 'report',
|
|
455
|
-
logo: '/admin/report.svg',
|
|
456
|
-
label: 'Report',
|
|
457
|
-
description: 'รายงานภาพรวมบริษัท',
|
|
458
|
-
to: routes.report.checkinSummaryDashboard.to,
|
|
459
|
-
status: StatusPortal.ACTIVE,
|
|
460
|
-
},
|
|
461
|
-
]
|
|
240
|
+
...(can(UserModule.TIMESHEET, ...ADMIN_SUPER)
|
|
241
|
+
? [toAdminApp(UserModule.TIMESHEET, routes.adminTimesheet.summaryReport.to, 'รายงานการบันทึกข้อมูลไทม์ชีท')]
|
|
462
242
|
: []),
|
|
463
|
-
...(
|
|
464
|
-
? [
|
|
465
|
-
{
|
|
466
|
-
name: 'tor',
|
|
467
|
-
logo: '/admin/tor.svg',
|
|
468
|
-
label: 'Presales Tools',
|
|
469
|
-
description: 'ระบบสร้างตารางเปรียบเทียบข้อกำหนด',
|
|
470
|
-
to: routes.tor.home.to,
|
|
471
|
-
status: StatusPortal.ACTIVE,
|
|
472
|
-
},
|
|
473
|
-
]
|
|
243
|
+
...(can(UserModule.SETTING, Permission.SUPER)
|
|
244
|
+
? [toAdminApp(UserModule.SETTING, routes.report.checkinSummaryDashboard.to, 'รายงานภาพรวมบริษัท')]
|
|
474
245
|
: []),
|
|
475
|
-
...(
|
|
476
|
-
? [
|
|
477
|
-
{
|
|
478
|
-
name: 'support',
|
|
479
|
-
logo: '/admin/support.svg',
|
|
480
|
-
label: 'Support',
|
|
481
|
-
description: 'Heatmap Monitor & Report',
|
|
482
|
-
to: routes.support.home.to,
|
|
483
|
-
status: StatusPortal.ACTIVE,
|
|
484
|
-
},
|
|
485
|
-
]
|
|
246
|
+
...(can(UserModule.TOR, ...USER_ADMIN_SUPER)
|
|
247
|
+
? [toApp(UserModule.TOR, routes.tor.home.to, 'ระบบสร้างตารางเปรียบเทียบข้อกำหนด')]
|
|
486
248
|
: []),
|
|
487
|
-
...(
|
|
488
|
-
? [
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
label: 'Document Flow',
|
|
493
|
-
description: 'ทะเบียนเอกสาร รับ-ส่ง',
|
|
494
|
-
to: routes.docsManagement.root.to,
|
|
495
|
-
status: StatusPortal.ACTIVE,
|
|
496
|
-
},
|
|
497
|
-
]
|
|
249
|
+
...(can(UserModule.SUPPORT, ...USER_ADMIN_SUPER)
|
|
250
|
+
? [toApp(UserModule.SUPPORT, routes.support.home.to, 'Heatmap Monitor & Report')]
|
|
251
|
+
: []),
|
|
252
|
+
...(can(UserModule.DOCUMENT, ...USER_ADMIN_SUPER)
|
|
253
|
+
? [toApp(UserModule.DOCUMENT, routes.docsManagement.root.to, 'ทะเบียนเอกสาร รับ-ส่ง')]
|
|
498
254
|
: []),
|
|
499
|
-
|
|
500
255
|
])
|
|
501
256
|
|
|
502
|
-
const financeApps = computed(() => [
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
? [
|
|
506
|
-
{
|
|
507
|
-
name: 'Quotation',
|
|
508
|
-
logo: '/admin/quotation.png',
|
|
509
|
-
label: 'Quotation',
|
|
510
|
-
description: 'รายรับรายจ่ายงบประมาณโครงการ',
|
|
511
|
-
to: routes.quotation.quotations.home.to,
|
|
512
|
-
status: StatusPortal.ACTIVE,
|
|
513
|
-
},
|
|
514
|
-
]
|
|
257
|
+
const financeApps = computed<IPortalApp[]>(() => [
|
|
258
|
+
...(can(UserModule.QUOTATION, ...USER_ADMIN_SUPER)
|
|
259
|
+
? [toApp(UserModule.QUOTATION, routes.quotation.quotations.home.to, 'รายรับรายจ่ายงบประมาณโครงการ')]
|
|
515
260
|
: []),
|
|
516
|
-
...(
|
|
517
|
-
? [
|
|
518
|
-
{
|
|
519
|
-
name: 'Cost Sheet',
|
|
520
|
-
logo: '/admin/cost-sheet.png',
|
|
521
|
-
label: 'Cost Sheet',
|
|
522
|
-
description: 'รายรับรายจ่ายงบประมาณโครงการ',
|
|
523
|
-
to: routes.costSheet.overview.to,
|
|
524
|
-
status: StatusPortal.ACTIVE,
|
|
525
|
-
},
|
|
526
|
-
]
|
|
261
|
+
...(can(UserModule.COSTSHEET, ...USER_ADMIN_SUPER)
|
|
262
|
+
? [toApp(UserModule.COSTSHEET, routes.costSheet.overview.to, 'รายรับรายจ่ายงบประมาณโครงการ')]
|
|
527
263
|
: []),
|
|
528
|
-
...(
|
|
529
|
-
? [
|
|
530
|
-
{
|
|
531
|
-
name: 'eFactoring',
|
|
532
|
-
logo: '/admin/efactoring.png',
|
|
533
|
-
label: 'eFactoring',
|
|
534
|
-
description: 'การเบิกเงินหมุนเวียนกับธนาคาร',
|
|
535
|
-
to: routes.eFactoring.dashboard.to,
|
|
536
|
-
status: StatusPortal.ACTIVE,
|
|
537
|
-
},
|
|
538
|
-
]
|
|
264
|
+
...(can(UserModule.EFACTORING, ...USER_ADMIN_SUPER)
|
|
265
|
+
? [toApp(UserModule.EFACTORING, routes.eFactoring.dashboard.to, 'การเบิกเงินหมุนเวียนกับธนาคาร')]
|
|
539
266
|
: []),
|
|
540
|
-
...(
|
|
541
|
-
? [
|
|
542
|
-
{
|
|
543
|
-
name: 'Guarantee',
|
|
544
|
-
logo: '/admin/guarantee.png',
|
|
545
|
-
label: 'งบค้ำประกัน',
|
|
546
|
-
description: 'การเบิกเงินค้ำซองและค้ำสัญญา',
|
|
547
|
-
to: routes.lg.overview.to,
|
|
548
|
-
status: StatusPortal.ACTIVE,
|
|
549
|
-
},
|
|
550
|
-
]
|
|
267
|
+
...(can(UserModule.LG, ...USER_ADMIN_SUPER)
|
|
268
|
+
? [toApp(UserModule.LG, routes.lg.overview.to, 'การเบิกเงินค้ำซองและค้ำสัญญา')]
|
|
551
269
|
: []),
|
|
552
|
-
...(
|
|
553
|
-
? [
|
|
554
|
-
{
|
|
555
|
-
name: 'Loan',
|
|
556
|
-
logo: '/admin/loan.svg',
|
|
557
|
-
label: 'Loan',
|
|
558
|
-
description: 'รายการกู้เงินจากธนาคาร',
|
|
559
|
-
to: routes.loan.list.lists.to,
|
|
560
|
-
status: StatusPortal.ACTIVE,
|
|
561
|
-
},
|
|
562
|
-
]
|
|
270
|
+
...(can(UserModule.LOAN, ...USER_ADMIN_SUPER)
|
|
271
|
+
? [toApp(UserModule.LOAN, routes.loan.list.lists.to, 'รายการกู้เงินจากธนาคาร')]
|
|
563
272
|
: []),
|
|
564
273
|
])
|
|
565
274
|
|
|
566
|
-
const peopleApps = computed(() => [
|
|
567
|
-
...(
|
|
568
|
-
? [
|
|
569
|
-
{
|
|
570
|
-
name: 'Employee',
|
|
571
|
-
logo: '/admin/employee.png',
|
|
572
|
-
label: 'Employee',
|
|
573
|
-
description: 'ระบบจัดการข้อมูลพนักงาน',
|
|
574
|
-
to: routes.employee.root.to,
|
|
575
|
-
status: StatusPortal.ACTIVE,
|
|
576
|
-
},
|
|
577
|
-
]
|
|
275
|
+
const peopleApps = computed<IPortalApp[]>(() => [
|
|
276
|
+
...(can(UserModule.EMPLOYEE, ...USER_ADMIN_SUPER)
|
|
277
|
+
? [toApp(UserModule.EMPLOYEE, routes.employee.root.to, 'ระบบจัดการข้อมูลพนักงาน')]
|
|
578
278
|
: []),
|
|
579
|
-
...(
|
|
580
|
-
? [
|
|
581
|
-
{
|
|
582
|
-
name: 'Newsletter',
|
|
583
|
-
logo: '/admin/newsletter.png',
|
|
584
|
-
label: 'Newsletter',
|
|
585
|
-
description: 'ระบบจัดการข่าวสาร',
|
|
586
|
-
to: routes.newsletter.announcement.announcements.to,
|
|
587
|
-
status: StatusPortal.ACTIVE,
|
|
588
|
-
},
|
|
589
|
-
]
|
|
279
|
+
...(can(UserModule.NEWSLETTER, ...USER_ADMIN_SUPER)
|
|
280
|
+
? [toApp(UserModule.NEWSLETTER, routes.newsletter.announcement.announcements.to, 'ระบบจัดการข่าวสาร')]
|
|
590
281
|
: []),
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
? [
|
|
594
|
-
{
|
|
595
|
-
name: 'Assets',
|
|
596
|
-
logo: '/admin/assets.png',
|
|
597
|
-
label: 'Assets',
|
|
598
|
-
description: 'ระบบจัดการสินทรัพย์',
|
|
599
|
-
to: routes.asset.dashboard.to,
|
|
600
|
-
status: StatusPortal.ACTIVE,
|
|
601
|
-
},
|
|
602
|
-
]
|
|
282
|
+
...(can(UserModule.ASSET, ...USER_ADMIN_SUPER)
|
|
283
|
+
? [toApp(UserModule.ASSET, routes.asset.dashboard.to, 'ระบบจัดการสินทรัพย์')]
|
|
603
284
|
: []),
|
|
604
|
-
...(
|
|
605
|
-
? [
|
|
606
|
-
{
|
|
607
|
-
name: 'Resource',
|
|
608
|
-
logo: '/admin/resource.svg',
|
|
609
|
-
label: 'Resource',
|
|
610
|
-
description: 'ระบบจัดการทรัพยากรบุคคล',
|
|
611
|
-
to: routes.resource.talentSearchAndCvBuilder.to,
|
|
612
|
-
status: StatusPortal.ACTIVE,
|
|
613
|
-
},
|
|
614
|
-
]
|
|
285
|
+
...(can(UserModule.RESOURCE, ...USER_ADMIN_SUPER)
|
|
286
|
+
? [toApp(UserModule.RESOURCE, routes.resource.talentSearchAndCvBuilder.to, 'ระบบจัดการทรัพยากรบุคคล')]
|
|
615
287
|
: []),
|
|
616
|
-
...(
|
|
617
|
-
? [
|
|
618
|
-
{
|
|
619
|
-
name: 'Request Admin',
|
|
620
|
-
logo: '/admin/request-admin.svg',
|
|
621
|
-
label: 'Request Admin',
|
|
622
|
-
description: 'ระบบจัดการคำขออนุมัติต่างๆ',
|
|
623
|
-
to: routes.requestAdmin.userRequest.users.to,
|
|
624
|
-
status: StatusPortal.ACTIVE,
|
|
625
|
-
},
|
|
626
|
-
]
|
|
288
|
+
...(can(UserModule.REQUEST, Permission.SUPER, Permission.ADMIN)
|
|
289
|
+
? [toAdminApp(UserModule.REQUEST, routes.requestAdmin.userRequest.users.to, 'ระบบจัดการคำขออนุมัติต่างๆ')]
|
|
627
290
|
: []),
|
|
628
|
-
...(
|
|
629
|
-
? [
|
|
630
|
-
{
|
|
631
|
-
name: 'Evaluation',
|
|
632
|
-
logo: '/admin/evaluation.png',
|
|
633
|
-
label: 'Evaluation',
|
|
634
|
-
description: 'ระบบจัดการการประเมิน',
|
|
635
|
-
to: routes.evaluation.general.generals.to,
|
|
636
|
-
status: StatusPortal.ACTIVE,
|
|
637
|
-
},
|
|
638
|
-
]
|
|
291
|
+
...(can(UserModule.EVALUATION, ...USER_ADMIN_SUPER)
|
|
292
|
+
? [toApp(UserModule.EVALUATION, routes.evaluation.general.generals.to, 'ระบบจัดการการประเมิน')]
|
|
639
293
|
: []),
|
|
640
|
-
...(
|
|
641
|
-
? [
|
|
642
|
-
{
|
|
643
|
-
name: 'Recruit',
|
|
644
|
-
logo: '/admin/recruit.png',
|
|
645
|
-
label: 'Recruit',
|
|
646
|
-
description: 'ระบบการสรรหาบุคลากร',
|
|
647
|
-
to: routes.recruit.root.to,
|
|
648
|
-
status: StatusPortal.ACTIVE,
|
|
649
|
-
},
|
|
650
|
-
]
|
|
294
|
+
...(can(UserModule.RECRUIT, ...ADMIN_SUPER)
|
|
295
|
+
? [toApp(UserModule.RECRUIT, routes.recruit.root.to, 'ระบบการสรรหาบุคลากร')]
|
|
651
296
|
: []),
|
|
652
|
-
|
|
653
297
|
])
|
|
654
298
|
|
|
655
|
-
const legalApps = computed(() => [
|
|
656
|
-
...(
|
|
657
|
-
? [
|
|
658
|
-
{
|
|
659
|
-
name: 'Contract',
|
|
660
|
-
logo: '/admin/contract.png',
|
|
661
|
-
label: 'Contract',
|
|
662
|
-
description: 'สร้างและจัดการสัญญา',
|
|
663
|
-
to: routes.legal.dashboard.to,
|
|
664
|
-
status: StatusPortal.ACTIVE,
|
|
665
|
-
},
|
|
666
|
-
]
|
|
299
|
+
const legalApps = computed<IPortalApp[]>(() => [
|
|
300
|
+
...(can(UserModule.CONTRACT, ...USER_ADMIN_SUPER)
|
|
301
|
+
? [toApp(UserModule.CONTRACT, routes.legal.dashboard.to, 'สร้างและจัดการสัญญา')]
|
|
667
302
|
: []),
|
|
668
303
|
])
|
|
304
|
+
|
|
305
|
+
const categories = computed<IPortalCategory[]>(() =>
|
|
306
|
+
[
|
|
307
|
+
{
|
|
308
|
+
key: 'daily',
|
|
309
|
+
title: 'Daily work Apps',
|
|
310
|
+
apps: dailyApps.value,
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
key: 'management',
|
|
314
|
+
title: 'Management',
|
|
315
|
+
apps: managementApps.value,
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
key: 'finance',
|
|
319
|
+
title: 'Finance',
|
|
320
|
+
apps: financeApps.value,
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
key: 'people',
|
|
324
|
+
title: 'People',
|
|
325
|
+
apps: peopleApps.value,
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
key: 'legal',
|
|
329
|
+
title: 'Legal',
|
|
330
|
+
apps: legalApps.value,
|
|
331
|
+
},
|
|
332
|
+
].filter((category) => category.apps.length > 0),
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
const filteredCategories = computed<IPortalCategory[]>(() => {
|
|
336
|
+
const keyword = search.value.trim().toLowerCase()
|
|
337
|
+
|
|
338
|
+
if (!keyword) {
|
|
339
|
+
return categories.value
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return categories.value
|
|
343
|
+
.map((category) => ({
|
|
344
|
+
...category,
|
|
345
|
+
apps: category.apps.filter((app) =>
|
|
346
|
+
app.label.toLowerCase().includes(keyword)
|
|
347
|
+
|| app.description.toLowerCase().includes(keyword),
|
|
348
|
+
),
|
|
349
|
+
}))
|
|
350
|
+
.filter((category) => category.apps.length > 0)
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
const gridColsClass = 'grid-cols-3 sm:grid-cols-4 lg:grid-cols-6 xl:grid-cols-7'
|
|
669
354
|
</script>
|