nuxt-layer-core 1.1.1 → 1.1.3

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.
@@ -1,245 +1,245 @@
1
- <template>
2
- <section id="dao-tao" class="py-24 bg-[#F7F9FB] border-t border-slate-200">
3
- <div class="max-w-7xl mx-auto px-6 lg:px-8" id="chi-phi">
4
- <div class="text-center mb-20">
5
- <span
6
- class="inline-block text-[#004AC6] font-bold uppercase tracking-widest text-xs mb-3 px-3 py-1 bg-blue-50 rounded-full">
7
- Chương trình đào tạo
8
- </span>
9
- <h3 class="font-['Montserrat'] font-extrabold text-3xl sm:text-4xl text-slate-900 mb-4">
10
- Các khóa đào tạo Proxmox VE
11
- </h3>
12
- <p class="text-slate-500 max-w-2xl mx-auto leading-relaxed">
13
- Nội dung bám sát chương trình chính thức của Proxmox, kết hợp lý thuyết chuyên sâu và thực hành trên hệ thống
14
- thực tế.
15
- </p>
16
- </div>
17
-
18
- <div class="grid grid-cols-1 md:grid-cols-3 gap-6 lg:gap-8">
19
- <div v-for="(plan, i) in formattedPlans" :key="plan.id" :data-delay="i * 150" class="course-card group relative"
20
- :class="plan.highlight ? 'md:-mt-6' : 'md:mt-0'">
21
- <!-- Glow nền cho card nổi bật -->
22
- <div v-if="plan.highlight"
23
- class="absolute -inset-3 bg-gradient-to-br from-[#004AC6]/25 via-blue-400/15 to-transparent rounded-[28px] blur-2xl opacity-70 -z-10">
24
- </div>
25
-
26
- <div
27
- class="relative bg-white rounded-2xl flex flex-col overflow-hidden transition-all duration-300 ease-out h-full"
28
- :class="plan.highlight
29
- ? 'ring-1 ring-[#004AC6]/15 shadow-[0_8px_30px_-6px_rgba(0,74,198,0.25)] hover:shadow-[0_20px_45px_-10px_rgba(0,74,198,0.35)] hover:-translate-y-1'
30
- : 'ring-1 ring-slate-200 shadow-[0_2px_10px_-2px_rgba(15,23,42,0.06)] hover:ring-blue-200 hover:shadow-[0_12px_30px_-8px_rgba(15,23,42,0.12)] hover:-translate-y-1'
31
- ">
32
- <div v-if="plan.highlight"
33
- class="bg-gradient-to-r from-[#004AC6] to-[#1D63E0] text-white text-[11px] font-bold py-2.5 text-center uppercase tracking-widest flex items-center justify-center gap-1.5">
34
- <Icon name="lucide:sparkles" class="w-3.5 h-3.5" />
35
- Được tư vấn chọn nhiều nhất
36
- </div>
37
-
38
- <div class="p-7 flex flex-col gap-5">
39
- <div class="flex justify-between items-start">
40
- <div
41
- class="w-12 h-12 rounded-xl flex items-center justify-center transition-transform duration-300 group-hover:scale-105"
42
- :class="plan.highlight
43
- ? 'bg-blue-50 text-[#004AC6] ring-4 ring-blue-50/70'
44
- : 'bg-slate-50 text-slate-400'
45
- ">
46
- <!-- <Icon :name="plan.icon" class="w-5 h-5" /> -->
47
- <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 34 512 444">
48
- <path
49
- d="M137.9 34.1c-10.5 0-19.7 1.9-28.5 5.7-8.6 3.8-16.2 8.9-22.9 15.6l170 186.4L426.1 55.3c-6.7-6.7-14.3-11.8-23.4-15.6-8.3-3.8-18-5.7-28-5.7-10.5 0-20.5 2.2-29.4 6.2-9.2 4-16.7 10-23.7 17l-65.2 72.2-66-72.2c-6.7-7-14.3-12.9-23.7-17-8.3-4-18.3-6.1-28.8-6.1M256.4 270l-170 186.7c6.7 6.5 14.3 11.8 22.9 15.6 8.9 3.8 18.1 5.7 28 5.7 11 0 20.5-2.4 29.4-6.2 9.4-4.3 17.5-10 24.2-17l65.5-72.2 65.4 72.2c6.7 7 14.3 12.7 23.4 17 8.9 3.8 18.6 6.2 29.4 6.2 10 0 19.7-1.9 28-5.7 9.2-3.8 16.7-9.2 23.4-15.6z"
50
- style="fill-rule:evenodd;clip-rule:evenodd" />
51
- <path
52
- d="M56 90.1c-10.8.3-21.3 2.4-30.7 6.5-9.7 4-18 9.7-25.3 16.7L129.8 256 0 398.5c7.3 7.3 15.6 12.9 25.3 17.2 9.4 4.3 19.9 6.2 30.7 6.7 11.6-.5 22.4-2.4 32.3-7.3q15-6.9 25.8-18.6l128-140.5-127.9-140.3c-7.8-7.5-16.2-13.7-26.1-18.6-10-4.6-20.5-6.7-32.1-7m399.7 0c-11.6.3-21.8 2.4-31.8 7-10 4.8-18.6 11-26.1 18.6L270.4 256l127.4 140.6q11.25 11.7 26.1 18.6c10 4.8 20.2 6.7 31.8 7.3 11.6-.5 21.5-2.4 31-6.7 10.2-4.3 18-10 25.3-17.2L382.5 256 512 113.3c-7.3-7-15.1-12.7-25.3-16.7-9.4-4.1-19.4-6.2-31-6.5"
53
- style="fill-rule:evenodd;clip-rule:evenodd;fill:#e57000" />
54
- </svg>
55
- </div>
56
-
57
- <span class="text-[10px] font-bold uppercase tracking-wider px-2.5 py-1 rounded-full" :class="plan.highlight
58
- ? 'bg-blue-50 text-[#004AC6]'
59
- : 'bg-slate-100 text-slate-500'
60
- ">
61
- {{ formatLevel(plan.level) }}
62
- </span>
63
- </div>
64
-
65
- <div>
66
- <h4 class="font-bold text-xl text-slate-900 mb-2">
67
- {{ plan.name }}
68
- </h4>
69
- <p class="text-slate-500 text-sm leading-relaxed">
70
- {{ plan.description }}
71
- </p>
72
- </div>
73
-
74
- <div class="pb-5 border-b border-slate-100">
75
- <span class="font-['Montserrat'] font-extrabold text-2xl text-slate-900">
76
- {{ plan.duration }}
77
- </span>
78
- <span class="text-slate-400 text-sm flex items-center gap-1.5 mt-2">
79
- <Icon name="lucide:monitor-play" class="w-4 h-4" />
80
- Online / thực hành
81
- </span>
82
- </div>
83
-
84
- <span class="text-[13px] text-slate-600 leading-loose [&_svg]:inline [&_svg]:text-[#004AC6]"
85
- v-html="plan.included"></span>
86
-
87
- <div v-if="plan.outcome" class="p-4 rounded-xl" :class="plan.highlight
88
- ? 'bg-gradient-to-br from-blue-50 to-indigo-50/60 border border-blue-100'
89
- : 'bg-slate-50 border border-slate-100'
90
- ">
91
- <span class="flex items-center gap-1.5 text-[10px] font-bold uppercase tracking-widest mb-2"
92
- :class="plan.highlight ? 'text-[#004AC6]' : 'text-slate-500'">
93
- <Icon name="lucide:target" class="w-3.5 h-3.5" />
94
- Kết quả đạt được
95
- </span>
96
- <p class="text-xs leading-relaxed font-semibold"
97
- :class="plan.highlight ? 'text-blue-900' : 'text-slate-700'">
98
- {{ plan.outcome }}
99
- </p>
100
- </div>
101
- </div>
102
-
103
- <div v-if="isConsultant" class="p-7 pt-2 mt-auto">
104
- <button @click="handleSelectPlan(plan)"
105
- class="w-full py-3.5 rounded-xl font-bold text-sm transition-all duration-300 cursor-pointer" :class="plan.highlight
106
- ? 'bg-[#004AC6] text-white shadow-lg shadow-blue-500/25 hover:bg-[#1D4ED8] hover:shadow-blue-500/40'
107
- : 'border border-slate-200 text-slate-600 hover:border-[#004AC6] hover:text-[#004AC6] hover:bg-blue-50/50'
108
- ">
109
- Liên hệ tư vấn
110
- </button>
111
- </div>
112
- </div>
113
- </div>
114
- </div>
115
- </div>
116
- </section>
117
- </template>
118
-
119
- <script setup>
120
- useScrollAnimate('.course-card', 'fade-up')
121
-
122
- const props = defineProps({
123
- targetCTA: { type: String, default: '' },
124
- slug: { type: String, default: '' },
125
- itemId01Groups01: { type: Object, default: null },
126
- itemId02Groups01: { type: Object, default: null },
127
- itemId03Groups01: { type: Object, default: null },
128
- itemId01Groups02: { type: Object, default: null },
129
- itemId02Groups02: { type: Object, default: null },
130
- itemId03Groups02: { type: Object, default: null },
131
- itemId01Groups03: { type: Object, default: null },
132
- itemId02Groups03: { type: Object, default: null },
133
- itemId03Groups03: { type: Object, default: null },
134
- })
135
-
136
- const isConsultant = computed(() => props.targetCTA === 'CONSULTANT')
137
- const router = useRouter()
138
-
139
- function handleSelectPlan(plan) {
140
- router.push({
141
- path: `/tu-van/khoa-hoc-proxmox`,
142
- query: {
143
- plan: plan.id,
144
- name: plan.name,
145
- level: plan.level,
146
- duration: plan.duration,
147
- description: plan.description || '',
148
- },
149
- })
150
- }
151
-
152
- function formatLevel(level) {
153
- const labels = {
154
- basic: 'Cơ bản',
155
- advanced: 'Nâng cao',
156
- expert: 'Chuyên gia',
157
- }
158
-
159
- return labels[level || ''] || level || ''
160
- }
161
-
162
- const samplePlans = [
163
- {
164
- id: 'sample-1',
165
- name: 'Deployment & Management',
166
- icon: 'lucide:graduation-cap',
167
- level: 'Nền tảng',
168
- duration: '14 giờ · Từ 2 buổi',
169
- description: 'Dành cho IT admin, kỹ sư hệ thống cần triển khai và quản trị ảo hóa trên máy chủ đơn.',
170
- included: [
171
- 'Kiến trúc, cài đặt & thiết lập hệ thống',
172
- 'Cấu hình mạng (Bridge, VLAN, SDN)',
173
- 'Lưu trữ nội bộ & quản lý VM/LXC',
174
- 'Backup & Restore qua giao diện/CLI',
175
- 'Phân quyền, xác thực & Tường lửa',
176
- 'Chuyển đổi V2V và P2V'
177
- ],
178
- highlight: false,
179
- outcome: 'Thành thạo triển khai, vận hành, sao lưu và xử lý sự cố trên máy chủ đơn lẻ.'
180
- },
181
- {
182
- id: 'sample-2',
183
- name: 'Clustering & Shared Storage',
184
- icon: 'lucide:network',
185
- level: 'Chuyên sâu',
186
- duration: '14 giờ · Từ 2 buổi',
187
- description: 'Kỹ sư cần xây dựng cụm, triển khai HA, Ceph và tối ưu hóa tài nguyên diện rộng.',
188
- included: [
189
- 'Kiến trúc cụm (Corosync, pmxcfs)',
190
- 'Triển khai lưu trữ siêu hội tụ Ceph',
191
- 'Tính sẵn sàng cao (HA) cho VM/LXC',
192
- 'Nhân bản đĩa ZFS (Replication)',
193
- 'Kịch bản sự cố & QDevice tiebreaker',
194
- 'Tự động hóa với REST API & CLI'
195
- ],
196
- highlight: true,
197
- outcome: 'Đủ năng lực quản trị cụm nhiều node, lưu trữ phân tán Ceph và duy trì HA an toàn.'
198
- },
199
- {
200
- id: 'sample-3',
201
- name: 'Proxmox VE Bundle',
202
- icon: 'lucide:package',
203
- level: 'Trọn gói',
204
- duration: '28 giờ · Từ 4-5 buổi',
205
- description: 'Deep dive nền tảng toàn diện: bao trọn kiến thức từ máy chủ đơn đến cụm phức tạp.',
206
- included: [
207
- 'Trọn bộ nội dung khóa Nền tảng',
208
- 'Trọn bộ nội dung khóa Chuyên sâu',
209
- 'Lab thực hành với môi trường thực tế',
210
- 'Hướng dẫn xử lý các ca lỗi production'
211
- ],
212
- highlight: false,
213
- outcome: 'Trở thành chuyên gia Proxmox thực thụ, sẵn sàng thi chứng chỉ và quản trị hạ tầng quy mô lớn.'
214
- }
215
- ]
216
-
217
- const rawItems = computed(() => [
218
- props.itemId01Groups01,
219
- props.itemId02Groups01,
220
- props.itemId03Groups01,
221
- props.itemId01Groups02,
222
- props.itemId02Groups02,
223
- props.itemId03Groups02,
224
- props.itemId01Groups03,
225
- props.itemId02Groups03,
226
- props.itemId03Groups03,
227
- ])
228
-
229
- const formattedPlans = computed(() => {
230
- const items = rawItems.value.map(normalizePlanItem).filter(Boolean)
231
- if (!items.length) return samplePlans
232
-
233
- return items.map((item, index) => ({
234
- id: item.id || `plan-${index}`,
235
- name: item.name,
236
- level: item.level,
237
- duration: item.duration,
238
- description: item.description,
239
- included: item.features,
240
- icon: item.icon,
241
- highlight: index === 1,
242
- outcome: '',
243
- }))
244
- })
1
+ <template>
2
+ <section id="dao-tao" class="py-24 bg-[#F7F9FB] border-t border-slate-200">
3
+ <div class="max-w-7xl mx-auto px-6 lg:px-8" id="chi-phi">
4
+ <div class="text-center mb-20">
5
+ <span
6
+ class="inline-block text-[#004AC6] font-bold uppercase tracking-widest text-xs mb-3 px-3 py-1 bg-blue-50 rounded-full">
7
+ Chương trình đào tạo
8
+ </span>
9
+ <h3 class="font-['Montserrat'] font-extrabold text-3xl sm:text-4xl text-slate-900 mb-4">
10
+ Các khóa đào tạo Proxmox VE
11
+ </h3>
12
+ <p class="text-slate-500 max-w-2xl mx-auto leading-relaxed">
13
+ Nội dung bám sát chương trình chính thức của Proxmox, kết hợp lý thuyết chuyên sâu và thực hành trên hệ thống
14
+ thực tế.
15
+ </p>
16
+ </div>
17
+
18
+ <div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3 lg:gap-8">
19
+ <div v-for="(plan, i) in formattedPlans" :key="plan.id" :data-delay="i * 150" class="course-card group relative"
20
+ :class="plan.highlight ? 'lg:-mt-6' : 'lg:mt-0'">
21
+ <!-- Glow nền cho card nổi bật -->
22
+ <div v-if="plan.highlight"
23
+ class="absolute -inset-3 bg-gradient-to-br from-[#004AC6]/25 via-blue-400/15 to-transparent rounded-[28px] blur-2xl opacity-70 -z-10">
24
+ </div>
25
+
26
+ <div
27
+ class="relative bg-white rounded-2xl flex flex-col overflow-hidden transition-all duration-300 ease-out h-full"
28
+ :class="plan.highlight
29
+ ? 'ring-1 ring-[#004AC6]/15 shadow-[0_8px_30px_-6px_rgba(0,74,198,0.25)] hover:shadow-[0_20px_45px_-10px_rgba(0,74,198,0.35)] hover:-translate-y-1'
30
+ : 'ring-1 ring-slate-200 shadow-[0_2px_10px_-2px_rgba(15,23,42,0.06)] hover:ring-blue-200 hover:shadow-[0_12px_30px_-8px_rgba(15,23,42,0.12)] hover:-translate-y-1'
31
+ ">
32
+ <div v-if="plan.highlight"
33
+ class="bg-gradient-to-r from-[#004AC6] to-[#1D63E0] text-white text-[11px] font-bold py-2.5 text-center uppercase tracking-widest flex items-center justify-center gap-1.5">
34
+ <Icon name="lucide:sparkles" class="w-3.5 h-3.5" />
35
+ Được tư vấn chọn nhiều nhất
36
+ </div>
37
+
38
+ <div class="p-7 flex flex-col gap-5">
39
+ <div class="flex justify-between items-start">
40
+ <div
41
+ class="w-12 h-12 rounded-xl flex items-center justify-center transition-transform duration-300 group-hover:scale-105"
42
+ :class="plan.highlight
43
+ ? 'bg-blue-50 text-[#004AC6] ring-4 ring-blue-50/70'
44
+ : 'bg-slate-50 text-slate-400'
45
+ ">
46
+ <!-- <Icon :name="plan.icon" class="w-5 h-5" /> -->
47
+ <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 34 512 444">
48
+ <path
49
+ d="M137.9 34.1c-10.5 0-19.7 1.9-28.5 5.7-8.6 3.8-16.2 8.9-22.9 15.6l170 186.4L426.1 55.3c-6.7-6.7-14.3-11.8-23.4-15.6-8.3-3.8-18-5.7-28-5.7-10.5 0-20.5 2.2-29.4 6.2-9.2 4-16.7 10-23.7 17l-65.2 72.2-66-72.2c-6.7-7-14.3-12.9-23.7-17-8.3-4-18.3-6.1-28.8-6.1M256.4 270l-170 186.7c6.7 6.5 14.3 11.8 22.9 15.6 8.9 3.8 18.1 5.7 28 5.7 11 0 20.5-2.4 29.4-6.2 9.4-4.3 17.5-10 24.2-17l65.5-72.2 65.4 72.2c6.7 7 14.3 12.7 23.4 17 8.9 3.8 18.6 6.2 29.4 6.2 10 0 19.7-1.9 28-5.7 9.2-3.8 16.7-9.2 23.4-15.6z"
50
+ style="fill-rule:evenodd;clip-rule:evenodd" />
51
+ <path
52
+ d="M56 90.1c-10.8.3-21.3 2.4-30.7 6.5-9.7 4-18 9.7-25.3 16.7L129.8 256 0 398.5c7.3 7.3 15.6 12.9 25.3 17.2 9.4 4.3 19.9 6.2 30.7 6.7 11.6-.5 22.4-2.4 32.3-7.3q15-6.9 25.8-18.6l128-140.5-127.9-140.3c-7.8-7.5-16.2-13.7-26.1-18.6-10-4.6-20.5-6.7-32.1-7m399.7 0c-11.6.3-21.8 2.4-31.8 7-10 4.8-18.6 11-26.1 18.6L270.4 256l127.4 140.6q11.25 11.7 26.1 18.6c10 4.8 20.2 6.7 31.8 7.3 11.6-.5 21.5-2.4 31-6.7 10.2-4.3 18-10 25.3-17.2L382.5 256 512 113.3c-7.3-7-15.1-12.7-25.3-16.7-9.4-4.1-19.4-6.2-31-6.5"
53
+ style="fill-rule:evenodd;clip-rule:evenodd;fill:#e57000" />
54
+ </svg>
55
+ </div>
56
+
57
+ <span class="text-[10px] font-bold uppercase tracking-wider px-2.5 py-1 rounded-full" :class="plan.highlight
58
+ ? 'bg-blue-50 text-[#004AC6]'
59
+ : 'bg-slate-100 text-slate-500'
60
+ ">
61
+ {{ formatLevel(plan.level) }}
62
+ </span>
63
+ </div>
64
+
65
+ <div>
66
+ <h4 class="font-bold text-xl text-slate-900 mb-2">
67
+ {{ plan.name }}
68
+ </h4>
69
+ <p class="text-slate-500 text-sm leading-relaxed">
70
+ {{ plan.description }}
71
+ </p>
72
+ </div>
73
+
74
+ <div class="pb-5 border-b border-slate-100">
75
+ <span class="font-['Montserrat'] font-extrabold text-2xl text-slate-900">
76
+ {{ plan.duration }}
77
+ </span>
78
+ <span class="text-slate-400 text-sm flex items-center gap-1.5 mt-2">
79
+ <Icon name="lucide:monitor-play" class="w-4 h-4" />
80
+ Online / thực hành
81
+ </span>
82
+ </div>
83
+
84
+ <span class="text-[13px] text-slate-600 leading-loose [&_svg]:inline [&_svg]:text-[#004AC6]"
85
+ v-html="plan.included"></span>
86
+
87
+ <div v-if="plan.outcome" class="p-4 rounded-xl" :class="plan.highlight
88
+ ? 'bg-gradient-to-br from-blue-50 to-indigo-50/60 border border-blue-100'
89
+ : 'bg-slate-50 border border-slate-100'
90
+ ">
91
+ <span class="flex items-center gap-1.5 text-[10px] font-bold uppercase tracking-widest mb-2"
92
+ :class="plan.highlight ? 'text-[#004AC6]' : 'text-slate-500'">
93
+ <Icon name="lucide:target" class="w-3.5 h-3.5" />
94
+ Kết quả đạt được
95
+ </span>
96
+ <p class="text-xs leading-relaxed font-semibold"
97
+ :class="plan.highlight ? 'text-blue-900' : 'text-slate-700'">
98
+ {{ plan.outcome }}
99
+ </p>
100
+ </div>
101
+ </div>
102
+
103
+ <div v-if="isConsultant" class="p-7 pt-2 mt-auto">
104
+ <button @click="handleSelectPlan(plan)"
105
+ class="w-full py-3.5 rounded-xl font-bold text-sm transition-all duration-300 cursor-pointer" :class="plan.highlight
106
+ ? 'bg-[#004AC6] text-white shadow-lg shadow-blue-500/25 hover:bg-[#1D4ED8] hover:shadow-blue-500/40'
107
+ : 'border border-slate-200 text-slate-600 hover:border-[#004AC6] hover:text-[#004AC6] hover:bg-blue-50/50'
108
+ ">
109
+ Liên hệ tư vấn
110
+ </button>
111
+ </div>
112
+ </div>
113
+ </div>
114
+ </div>
115
+ </div>
116
+ </section>
117
+ </template>
118
+
119
+ <script setup>
120
+ useScrollAnimate('.course-card', 'fade-up')
121
+
122
+ const props = defineProps({
123
+ targetCTA: { type: String, default: '' },
124
+ slug: { type: String, default: '' },
125
+ itemId01Groups01: { type: Object, default: null },
126
+ itemId02Groups01: { type: Object, default: null },
127
+ itemId03Groups01: { type: Object, default: null },
128
+ itemId01Groups02: { type: Object, default: null },
129
+ itemId02Groups02: { type: Object, default: null },
130
+ itemId03Groups02: { type: Object, default: null },
131
+ itemId01Groups03: { type: Object, default: null },
132
+ itemId02Groups03: { type: Object, default: null },
133
+ itemId03Groups03: { type: Object, default: null },
134
+ })
135
+
136
+ const isConsultant = computed(() => props.targetCTA === 'CONSULTANT')
137
+ const router = useRouter()
138
+
139
+ function handleSelectPlan(plan) {
140
+ router.push({
141
+ path: `/tu-van/khoa-hoc-proxmox`,
142
+ query: {
143
+ plan: plan.id,
144
+ name: plan.name,
145
+ level: plan.level,
146
+ duration: plan.duration,
147
+ description: plan.description || '',
148
+ },
149
+ })
150
+ }
151
+
152
+ function formatLevel(level) {
153
+ const labels = {
154
+ basic: 'Cơ bản',
155
+ advanced: 'Nâng cao',
156
+ expert: 'Chuyên gia',
157
+ }
158
+
159
+ return labels[level || ''] || level || ''
160
+ }
161
+
162
+ const samplePlans = [
163
+ {
164
+ id: 'sample-1',
165
+ name: 'Deployment & Management',
166
+ icon: 'lucide:graduation-cap',
167
+ level: 'Nền tảng',
168
+ duration: '14 giờ · Từ 2 buổi',
169
+ description: 'Dành cho IT admin, kỹ sư hệ thống cần triển khai và quản trị ảo hóa trên máy chủ đơn.',
170
+ included: [
171
+ 'Kiến trúc, cài đặt & thiết lập hệ thống',
172
+ 'Cấu hình mạng (Bridge, VLAN, SDN)',
173
+ 'Lưu trữ nội bộ & quản lý VM/LXC',
174
+ 'Backup & Restore qua giao diện/CLI',
175
+ 'Phân quyền, xác thực & Tường lửa',
176
+ 'Chuyển đổi V2V và P2V'
177
+ ],
178
+ highlight: false,
179
+ outcome: 'Thành thạo triển khai, vận hành, sao lưu và xử lý sự cố trên máy chủ đơn lẻ.'
180
+ },
181
+ {
182
+ id: 'sample-2',
183
+ name: 'Clustering & Shared Storage',
184
+ icon: 'lucide:network',
185
+ level: 'Chuyên sâu',
186
+ duration: '14 giờ · Từ 2 buổi',
187
+ description: 'Kỹ sư cần xây dựng cụm, triển khai HA, Ceph và tối ưu hóa tài nguyên diện rộng.',
188
+ included: [
189
+ 'Kiến trúc cụm (Corosync, pmxcfs)',
190
+ 'Triển khai lưu trữ siêu hội tụ Ceph',
191
+ 'Tính sẵn sàng cao (HA) cho VM/LXC',
192
+ 'Nhân bản đĩa ZFS (Replication)',
193
+ 'Kịch bản sự cố & QDevice tiebreaker',
194
+ 'Tự động hóa với REST API & CLI'
195
+ ],
196
+ highlight: true,
197
+ outcome: 'Đủ năng lực quản trị cụm nhiều node, lưu trữ phân tán Ceph và duy trì HA an toàn.'
198
+ },
199
+ {
200
+ id: 'sample-3',
201
+ name: 'Proxmox VE Bundle',
202
+ icon: 'lucide:package',
203
+ level: 'Trọn gói',
204
+ duration: '28 giờ · Từ 4-5 buổi',
205
+ description: 'Deep dive nền tảng toàn diện: bao trọn kiến thức từ máy chủ đơn đến cụm phức tạp.',
206
+ included: [
207
+ 'Trọn bộ nội dung khóa Nền tảng',
208
+ 'Trọn bộ nội dung khóa Chuyên sâu',
209
+ 'Lab thực hành với môi trường thực tế',
210
+ 'Hướng dẫn xử lý các ca lỗi production'
211
+ ],
212
+ highlight: false,
213
+ outcome: 'Trở thành chuyên gia Proxmox thực thụ, sẵn sàng thi chứng chỉ và quản trị hạ tầng quy mô lớn.'
214
+ }
215
+ ]
216
+
217
+ const rawItems = computed(() => [
218
+ props.itemId01Groups01,
219
+ props.itemId02Groups01,
220
+ props.itemId03Groups01,
221
+ props.itemId01Groups02,
222
+ props.itemId02Groups02,
223
+ props.itemId03Groups02,
224
+ props.itemId01Groups03,
225
+ props.itemId02Groups03,
226
+ props.itemId03Groups03,
227
+ ])
228
+
229
+ const formattedPlans = computed(() => {
230
+ const items = rawItems.value.map(normalizePlanItem).filter(Boolean)
231
+ if (!items.length) return samplePlans
232
+
233
+ return items.map((item, index) => ({
234
+ id: item.id || `plan-${index}`,
235
+ name: item.name,
236
+ level: item.level,
237
+ duration: item.duration,
238
+ description: item.description,
239
+ included: item.features,
240
+ icon: item.icon,
241
+ highlight: index === 1,
242
+ outcome: '',
243
+ }))
244
+ })
245
245
  </script>