nuxt-layer-core 2.0.1
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/.claude/settings.local.json +8 -0
- package/app/app.config.ts +5 -0
- package/app/app.vue +11 -0
- package/app/assets/css/main.css +113 -0
- package/app/components/.gitkeep +0 -0
- package/app/components/ui/sonner/Sonner.vue +62 -0
- package/app/components/ui/sonner/index.ts +1 -0
- package/app/composables/.gitkeep +0 -0
- package/app/layers/solution/app/assets/proxmox-css/main.css +89 -0
- package/app/layers/solution/app/assets/proxmox-css/proxmox-utils.css +68 -0
- package/app/layers/solution/app/components/ClusterDiagram.vue +72 -0
- package/app/layers/solution/app/components/CoursesSection.vue +246 -0
- package/app/layers/solution/app/components/CtaSection.vue +329 -0
- package/app/layers/solution/app/components/FeaturesSection.vue +67 -0
- package/app/layers/solution/app/components/HeroSection.vue +144 -0
- package/app/layers/solution/app/components/PricingPlansSection.vue +434 -0
- package/app/layers/solution/app/components/RegistrationForm.vue +256 -0
- package/app/layers/solution/app/components/TestimonialsSection.vue +58 -0
- package/app/layers/solution/app/components/TheFooter.vue +61 -0
- package/app/layers/solution/app/components/TheHeader.vue +189 -0
- package/app/layers/solution/app/components/proxmox/AppIcon.vue +45 -0
- package/app/layers/solution/app/components/proxmox/ComparisonSection.vue +54 -0
- package/app/layers/solution/app/components/proxmox/FaqSection.vue +58 -0
- package/app/layers/solution/app/components/proxmox/HciOverviewSection.vue +37 -0
- package/app/layers/solution/app/components/proxmox/HeroSection.vue +74 -0
- package/app/layers/solution/app/components/proxmox/TestimonialsSection.vue +44 -0
- package/app/layers/solution/app/components/proxmox/TrainingBenefitsSection.vue +37 -0
- package/app/layers/solution/app/components/proxmox/VeFeaturesSection.vue +55 -0
- package/app/layers/solution/app/composables/useActiveSection.ts +47 -0
- package/app/layers/solution/app/composables/useAuthApi.ts +244 -0
- package/app/layers/solution/app/composables/useAuthState.ts +16 -0
- package/app/layers/solution/app/composables/useCookie.ts +79 -0
- package/app/layers/solution/app/composables/useCookieHelper.ts +81 -0
- package/app/layers/solution/app/composables/useCrmApi.ts +32 -0
- package/app/layers/solution/app/composables/useDynamicCollection.ts +23 -0
- package/app/layers/solution/app/composables/useScrollAnimate.ts +40 -0
- package/app/layers/solution/app/composables/useScrollToSection.ts +13 -0
- package/app/layers/solution/app/composables/useSolutionApi.ts +55 -0
- package/app/layers/solution/app/composables/useToast.ts +14 -0
- package/app/layers/solution/app/data/proxmox-content.ts +158 -0
- package/app/layers/solution/app/images/Proxmox HCI.png +0 -0
- package/app/layers/solution/app/images/image_from_https_hercules_cdn.com_file_6dztkvkfnip0ud23tzzvu57c.png +0 -0
- package/app/layers/solution/app/layouts/default.vue +5 -0
- package/app/layers/solution/app/nuxt.config.ts +9 -0
- package/app/layers/solution/app/pages/cap-nhat-thong-tin/index.vue +302 -0
- package/app/layers/solution/app/pages/dang-ky/index.vue +627 -0
- package/app/layers/solution/app/pages/dang-nhap/index.vue +208 -0
- package/app/layers/solution/app/pages/doi-mat-khau/index.vue +237 -0
- package/app/layers/solution/app/pages/giai-phap-proxmox/[slug]/index.vue +37 -0
- package/app/layers/solution/app/pages/giai-phap-proxmox/[slug]/proxmox-hci/index.vue +45 -0
- package/app/layers/solution/app/pages/giai-phap-proxmox/dang-ky-khoa-hoc/[slug].vue +131 -0
- package/app/layers/solution/app/pages/quen-mat-khau/index.vue +136 -0
- package/app/layers/solution/app/pages/xac-thuc/index.vue +320 -0
- package/app/layers/solution/app/plugins/reveal.ts +56 -0
- package/app/layers/solution/app/public/images/image_from_https_hercules_cdn.com_file_6dztkvkfnip0ud23tzzvu57c.png +0 -0
- package/app/layers/solution/app/public/images/logo-lvs-1300x330.png +0 -0
- package/app/layouts/auth.vue +71 -0
- package/app/lib/utils.ts +7 -0
- package/app/middleware/.gitkeep +0 -0
- package/app/modules/layer-route-priority.ts +60 -0
- package/app/pages/index.vue +9 -0
- package/app/pages/san-pham-proxmox.vue +8 -0
- package/app/plugins/.gitkeep +0 -0
- package/app/plugins/sdk.ts +29 -0
- package/app/stores/.gitkeep +0 -0
- package/app/types/sdk.d.ts +15 -0
- package/components.json +24 -0
- package/nuxt.config.ts +104 -0
- package/package.json +52 -0
- package/public/.gitkeep +0 -0
- package/server/api/.gitkeep +0 -0
- package/server/utils/.gitkeep +0 -0
- package/tailwind.config.js +96 -0
- package/tsconfig.base.json +18 -0
- package/tsconfig.json +18 -0
- package/website-longvan-1.1.6.tgz +0 -0
- package/website-longvan-1.1.7.tgz +0 -0
- package/website-longvan-1.1.8.tgz +0 -0
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section id="goi-san-pham" ref="sectionRoot" class="py-24 bg-white overflow-hidden" :class="{ 'pricing-revealed': revealed }">
|
|
3
|
+
<div class="max-w-6xl mx-auto px-6 lg:px-8">
|
|
4
|
+
<div class="text-center mb-12 pricing-header">
|
|
5
|
+
<h2 class="text-[#004AC6] font-bold uppercase tracking-widest text-sm mb-2">Gói sản phẩm</h2>
|
|
6
|
+
<h3 class="font-['Montserrat'] font-extrabold text-2xl sm:text-4xl text-slate-900 mb-4">
|
|
7
|
+
Chọn gói phù hợp<br class="hidden sm:block" />
|
|
8
|
+
với nhu cầu của bạn
|
|
9
|
+
</h3>
|
|
10
|
+
<p class="text-slate-500 max-w-2xl mx-auto leading-relaxed">
|
|
11
|
+
Thuê hạ tầng Proxmox HCI theo tháng, tham gia workshop 1 ngày hoặc chọn khóa đào tạo chuyên sâu. Chi phí
|
|
12
|
+
minh bạch, điều chỉnh theo yêu cầu riêng.
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<div class="flex flex-wrap items-center justify-center gap-3 mt-8">
|
|
16
|
+
<button
|
|
17
|
+
v-for="tab in tabs"
|
|
18
|
+
:key="tab.id"
|
|
19
|
+
type="button"
|
|
20
|
+
@click="activeTab = tab.id"
|
|
21
|
+
class="inline-flex items-center gap-2 px-5 py-2.5 rounded-full text-sm font-bold transition-all duration-300 cursor-pointer"
|
|
22
|
+
:class="activeTab === tab.id
|
|
23
|
+
? 'bg-[#004AC6] text-white shadow-lg shadow-blue-500/25 scale-[1.03]'
|
|
24
|
+
: 'bg-white text-slate-500 border border-slate-200 hover:border-blue-200 hover:text-[#004AC6]'
|
|
25
|
+
"
|
|
26
|
+
>
|
|
27
|
+
<Icon :name="tab.icon" class="w-4 h-4" />
|
|
28
|
+
{{ tab.label }}
|
|
29
|
+
</button>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<Transition name="fade-swap" mode="out-in">
|
|
33
|
+
<p :key="activeTab" class="text-slate-400 text-sm max-w-xl mx-auto mt-5">
|
|
34
|
+
{{ activeTabData.intro }}
|
|
35
|
+
</p>
|
|
36
|
+
</Transition>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<Transition name="fade-swap" mode="out-in">
|
|
40
|
+
<div :key="activeTab">
|
|
41
|
+
<!-- Info cards: only for Proxmox HCI -->
|
|
42
|
+
<div v-if="activeTab === 'hci'" class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-16">
|
|
43
|
+
<div
|
|
44
|
+
v-for="(info, i) in hciInfoCards"
|
|
45
|
+
:key="info.title"
|
|
46
|
+
class="pricing-reveal bg-white rounded-2xl border border-slate-200 p-6 hover:border-blue-200 hover:shadow-lg transition-all duration-300"
|
|
47
|
+
:style="{ '--i': i }"
|
|
48
|
+
>
|
|
49
|
+
<div class="w-11 h-11 rounded-[10px] bg-blue-50 flex items-center justify-center mb-5 text-[#004AC6]">
|
|
50
|
+
<Icon :name="info.icon" class="w-5 h-5" />
|
|
51
|
+
</div>
|
|
52
|
+
<h4 class="font-bold text-slate-900 mb-2">{{ info.title }}</h4>
|
|
53
|
+
<p class="text-sm text-slate-500 leading-relaxed">{{ info.desc }}</p>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<!-- Billing period switch: only for Proxmox HCI -->
|
|
58
|
+
<div v-if="activeTab === 'hci'" class="flex flex-col items-center gap-4 mb-10">
|
|
59
|
+
<p class="text-slate-500 text-sm">Chọn kỳ hạn thuê, càng dài chi phí hàng tháng càng thấp</p>
|
|
60
|
+
<div class="inline-flex items-center gap-1 bg-white border border-slate-200 rounded-full p-1">
|
|
61
|
+
<button
|
|
62
|
+
v-for="period in billingPeriods"
|
|
63
|
+
:key="period.value"
|
|
64
|
+
type="button"
|
|
65
|
+
@click="activePeriod = period.value"
|
|
66
|
+
class="px-4 py-2 rounded-full text-sm font-semibold transition-all duration-300 cursor-pointer"
|
|
67
|
+
:class="activePeriod === period.value
|
|
68
|
+
? 'bg-[#004AC6] text-white shadow-md shadow-blue-500/25'
|
|
69
|
+
: 'text-slate-500 hover:text-[#004AC6]'
|
|
70
|
+
"
|
|
71
|
+
>
|
|
72
|
+
{{ period.label }}
|
|
73
|
+
</button>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<!-- Pricing cards -->
|
|
78
|
+
<Transition name="fade-swap" mode="out-in">
|
|
79
|
+
<div :key="activeTab + '-' + activePeriod" class="grid grid-cols-1 md:grid-cols-3 gap-6 lg:gap-8">
|
|
80
|
+
<div
|
|
81
|
+
v-for="(plan, i) in activePlans"
|
|
82
|
+
:key="plan.name"
|
|
83
|
+
class="pricing-reveal group relative"
|
|
84
|
+
:style="{ '--i': i }"
|
|
85
|
+
:class="plan.highlight ? 'md:-mt-6' : 'md:mt-0'"
|
|
86
|
+
>
|
|
87
|
+
<div
|
|
88
|
+
v-if="plan.highlight"
|
|
89
|
+
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"
|
|
90
|
+
></div>
|
|
91
|
+
|
|
92
|
+
<div
|
|
93
|
+
class="relative bg-white rounded-2xl flex flex-col overflow-hidden h-full transition-all duration-300 ease-out"
|
|
94
|
+
:class="plan.highlight
|
|
95
|
+
? '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'
|
|
96
|
+
: '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'
|
|
97
|
+
"
|
|
98
|
+
>
|
|
99
|
+
<div
|
|
100
|
+
v-if="plan.highlight"
|
|
101
|
+
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"
|
|
102
|
+
>
|
|
103
|
+
<Icon name="lucide:star" class="w-3.5 h-3.5" />
|
|
104
|
+
Được chọn nhiều nhất
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<div class="p-7 flex flex-col gap-4">
|
|
108
|
+
<div>
|
|
109
|
+
<h4 class="font-bold text-xl text-slate-900 mb-2">{{ plan.name }}</h4>
|
|
110
|
+
<p class="text-slate-500 text-sm leading-relaxed">{{ plan.desc }}</p>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<div class="pb-1">
|
|
114
|
+
<span v-if="plan.contact" class="font-['Montserrat'] font-extrabold text-2xl text-[#004AC6]">
|
|
115
|
+
Liên hệ
|
|
116
|
+
</span>
|
|
117
|
+
<template v-else>
|
|
118
|
+
<span class="font-['Montserrat'] font-extrabold text-2xl sm:text-[28px] text-slate-900">
|
|
119
|
+
{{ plan.priceLabel }}{{ formatPrice(plan.price) }}đ
|
|
120
|
+
</span>
|
|
121
|
+
<span class="text-slate-400 text-sm">{{ plan.unit }}</span>
|
|
122
|
+
</template>
|
|
123
|
+
<p class="text-slate-400 text-xs mt-1.5">{{ plan.priceNote }}</p>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<div class="flex flex-wrap gap-1.5">
|
|
127
|
+
<span
|
|
128
|
+
v-for="tag in plan.tags"
|
|
129
|
+
:key="tag"
|
|
130
|
+
class="text-[11px] font-medium text-slate-500 bg-slate-50 border border-slate-100 rounded-md px-2 py-1"
|
|
131
|
+
>
|
|
132
|
+
{{ tag }}
|
|
133
|
+
</span>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<ul class="flex flex-col gap-2.5 pt-4 border-t border-slate-100">
|
|
137
|
+
<li
|
|
138
|
+
v-for="feature in plan.features"
|
|
139
|
+
:key="feature"
|
|
140
|
+
class="flex items-start gap-2 text-sm text-slate-600"
|
|
141
|
+
>
|
|
142
|
+
<Icon name="lucide:check" class="w-4 h-4 text-[#004AC6] mt-0.5 shrink-0" />
|
|
143
|
+
{{ feature }}
|
|
144
|
+
</li>
|
|
145
|
+
</ul>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
<div class="p-7 pt-2 mt-auto">
|
|
149
|
+
<button
|
|
150
|
+
type="button"
|
|
151
|
+
class="w-full py-3.5 rounded-xl font-bold text-sm transition-all duration-300 cursor-pointer"
|
|
152
|
+
:class="plan.highlight
|
|
153
|
+
? 'bg-[#004AC6] text-white shadow-lg shadow-blue-500/25 hover:bg-[#1D4ED8] hover:shadow-blue-500/40'
|
|
154
|
+
: 'border border-slate-200 text-slate-600 hover:border-[#004AC6] hover:text-[#004AC6] hover:bg-blue-50/50'
|
|
155
|
+
"
|
|
156
|
+
>
|
|
157
|
+
{{ activeTabData.cta }}
|
|
158
|
+
</button>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
</Transition>
|
|
164
|
+
</div>
|
|
165
|
+
</Transition>
|
|
166
|
+
</div>
|
|
167
|
+
</section>
|
|
168
|
+
</template>
|
|
169
|
+
|
|
170
|
+
<script setup>
|
|
171
|
+
useScrollAnimate('.pricing-header', 'fade-up')
|
|
172
|
+
|
|
173
|
+
const sectionRoot = ref(null)
|
|
174
|
+
const revealed = ref(false)
|
|
175
|
+
|
|
176
|
+
onMounted(() => {
|
|
177
|
+
const observer = new IntersectionObserver(
|
|
178
|
+
(entries) => {
|
|
179
|
+
for (const entry of entries) {
|
|
180
|
+
if (entry.isIntersecting) {
|
|
181
|
+
revealed.value = true
|
|
182
|
+
observer.disconnect()
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
{ threshold: 0.15 }
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
if (sectionRoot.value) observer.observe(sectionRoot.value)
|
|
190
|
+
onUnmounted(() => observer.disconnect())
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
const activeTab = ref('hci')
|
|
194
|
+
const activePeriod = ref(36)
|
|
195
|
+
|
|
196
|
+
const tabs = [
|
|
197
|
+
{ id: 'hci', label: 'Proxmox HCI', icon: 'lucide:server-cog' },
|
|
198
|
+
{ id: 'workshop', label: 'Workshop 1 ngày', icon: 'lucide:zap' },
|
|
199
|
+
{ id: 'training', label: 'Đào tạo Proxmox', icon: 'lucide:layers' },
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
const billingPeriods = [
|
|
203
|
+
{ value: 12, label: 'Thuê 12 tháng' },
|
|
204
|
+
{ value: 24, label: 'Thuê 24 tháng' },
|
|
205
|
+
{ value: 36, label: 'Thuê 36 tháng' },
|
|
206
|
+
]
|
|
207
|
+
|
|
208
|
+
const hciInfoCards = [
|
|
209
|
+
{
|
|
210
|
+
icon: 'lucide:server',
|
|
211
|
+
title: 'Thuê trọn gói tại DC của chúng tôi',
|
|
212
|
+
desc: 'Cụm đặt tại trung tâm dữ liệu Tier III, gồm phần cứng, điện, mạng và vận hành. Bạn chỉ dùng và trả phí hàng tháng.',
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
icon: 'lucide:building-2',
|
|
216
|
+
title: 'Thuê phần cứng đặt tại doanh nghiệp',
|
|
217
|
+
desc: 'Chúng tôi mang thiết bị tới đặt tại phòng máy của bạn, triển khai và bảo hành. Dữ liệu nằm trong nội bộ, không cần đầu tư ban đầu.',
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
icon: 'lucide:refresh-cw',
|
|
221
|
+
title: 'Thuê linh hoạt theo node',
|
|
222
|
+
desc: 'Thêm hoặc bớt node theo từng tháng khi nhu cầu thay đổi. Có tùy chọn chuyển quyền sở hữu thiết bị khi hết hạn thuê.',
|
|
223
|
+
},
|
|
224
|
+
]
|
|
225
|
+
|
|
226
|
+
const hciPlans = [
|
|
227
|
+
{
|
|
228
|
+
name: 'HCI Starter',
|
|
229
|
+
desc: 'Cụm 3 node cho doanh nghiệp vừa và nhỏ',
|
|
230
|
+
unit: '/tháng',
|
|
231
|
+
priceLabel: '',
|
|
232
|
+
prices: { 12: 14900000, 24: 11900000, 36: 9900000 },
|
|
233
|
+
tags: ['3 node x86', 'Ceph 3 bản sao', '10 GbE nội cụm', '~20 TB khả dụng'],
|
|
234
|
+
features: [
|
|
235
|
+
'Không chi phí đầu tư thiết bị ban đầu',
|
|
236
|
+
'Triển khai, tinh chỉnh và bật High Availability',
|
|
237
|
+
'Bảo hành, thay thế phần cứng trong suốt thời gian thuê',
|
|
238
|
+
'Đào tạo vận hành 1 buổi cho đội IT',
|
|
239
|
+
],
|
|
240
|
+
highlight: false,
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
name: 'HCI Pro',
|
|
244
|
+
desc: 'Cụm mở rộng cho hệ thống production',
|
|
245
|
+
unit: '/tháng',
|
|
246
|
+
priceLabel: '',
|
|
247
|
+
prices: { 12: 27900000, 24: 23900000, 36: 20900000 },
|
|
248
|
+
tags: ['5 node NVMe', 'Ceph RBD + CephFS', '25 GbE dự phòng', '~60 TB khả dụng'],
|
|
249
|
+
features: [
|
|
250
|
+
'Proxmox Backup Server riêng đi kèm',
|
|
251
|
+
'SDN, firewall phân tầng cho từng VM',
|
|
252
|
+
'Giám sát, cảnh báo toàn cụm 24/7',
|
|
253
|
+
'Nâng cấp cấu hình giữa kỳ không phát sinh phí ký lại',
|
|
254
|
+
],
|
|
255
|
+
highlight: true,
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
name: 'HCI Datacenter',
|
|
259
|
+
desc: 'Đa site, khôi phục thảm họa',
|
|
260
|
+
unit: '',
|
|
261
|
+
contact: true,
|
|
262
|
+
tags: ['Từ 8 node', 'Ceph đa pool', 'Mạng lõi 100 GbE', 'Dung lượng theo yêu cầu'],
|
|
263
|
+
features: [
|
|
264
|
+
'Nhân bản chéo hai trung tâm dữ liệu',
|
|
265
|
+
'Kịch bản DR và diễn tập định kỳ',
|
|
266
|
+
'Tự động hóa qua API/Terraform',
|
|
267
|
+
'Kỹ sư trực onsite theo SLA cam kết',
|
|
268
|
+
],
|
|
269
|
+
highlight: false,
|
|
270
|
+
},
|
|
271
|
+
]
|
|
272
|
+
|
|
273
|
+
const workshopPlans = [
|
|
274
|
+
{
|
|
275
|
+
name: 'Workshop Trực tuyến',
|
|
276
|
+
desc: 'Tham gia từ xa · lab riêng trên cloud',
|
|
277
|
+
unit: '/học viên',
|
|
278
|
+
priceLabel: '',
|
|
279
|
+
price: 2900000,
|
|
280
|
+
priceNote: '',
|
|
281
|
+
tags: ['1 ngày · 8 giờ', 'Trực tuyến', 'Lab cloud riêng'],
|
|
282
|
+
features: [
|
|
283
|
+
'Cài đặt Proxmox VE từ số 0',
|
|
284
|
+
'Dựng cụm HCI với Ceph, bật High Availability',
|
|
285
|
+
'Ghi hình buổi học để xem lại 30 ngày',
|
|
286
|
+
'Checklist triển khai dùng ngay',
|
|
287
|
+
],
|
|
288
|
+
highlight: false,
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
name: 'Workshop Tại lớp',
|
|
292
|
+
desc: 'Học trực tiếp cùng giảng viên',
|
|
293
|
+
unit: '/học viên',
|
|
294
|
+
priceLabel: '',
|
|
295
|
+
price: 3900000,
|
|
296
|
+
priceNote: '',
|
|
297
|
+
tags: ['1 ngày · 8 giờ', 'Tại lớp', 'Thiết bị thật tại lab'],
|
|
298
|
+
features: [
|
|
299
|
+
'Thao tác trực tiếp trên cụm nhiều node',
|
|
300
|
+
'Mô phỏng sự cố node và tự phục hồi',
|
|
301
|
+
'Hỏi đáp 1-1 với giảng viên',
|
|
302
|
+
'Suất ăn trưa và tài liệu in kèm',
|
|
303
|
+
],
|
|
304
|
+
highlight: true,
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
name: 'Workshop Nội bộ doanh nghiệp',
|
|
308
|
+
desc: 'Tổ chức riêng cho đội IT của bạn',
|
|
309
|
+
unit: '/lớp tối đa 15 người',
|
|
310
|
+
priceLabel: 'Từ ',
|
|
311
|
+
price: 39000000,
|
|
312
|
+
priceNote: '',
|
|
313
|
+
tags: ['1-2 ngày', 'Tại doanh nghiệp', 'Nội dung tùy chỉnh'],
|
|
314
|
+
features: [
|
|
315
|
+
'Nội dung thiết kế theo hạ tầng hiện có',
|
|
316
|
+
'Giảng viên và thiết bị lab tới tận nơi',
|
|
317
|
+
'Đánh giá năng lực đội IT sau workshop',
|
|
318
|
+
'Ưu đãi khi kết hợp gói thuê HCI',
|
|
319
|
+
],
|
|
320
|
+
highlight: false,
|
|
321
|
+
},
|
|
322
|
+
]
|
|
323
|
+
|
|
324
|
+
const trainingPlans = [
|
|
325
|
+
{
|
|
326
|
+
name: 'Deployment & Management',
|
|
327
|
+
desc: 'Nền tảng · máy chủ đơn',
|
|
328
|
+
unit: '/học viên',
|
|
329
|
+
priceLabel: 'Từ ',
|
|
330
|
+
price: 9900000,
|
|
331
|
+
priceNote: '',
|
|
332
|
+
tags: ['14 giờ · 2 buổi', 'Trực tuyến hoặc tại lớp', 'Lab thực hành riêng'],
|
|
333
|
+
features: ['Cài đặt, mạng, lưu trữ, VM/LXC', 'Backup, phân quyền, tường lửa', 'Chứng nhận hoàn thành Proxmox'],
|
|
334
|
+
highlight: false,
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
name: 'Clustering & Shared Storage',
|
|
338
|
+
desc: 'Chuyên sâu · cụm và Ceph',
|
|
339
|
+
unit: '/học viên',
|
|
340
|
+
priceLabel: 'Từ ',
|
|
341
|
+
price: 11900000,
|
|
342
|
+
priceNote: '',
|
|
343
|
+
tags: ['14 giờ · 2 buổi', 'Trực tuyến hoặc tại lớp', 'Lab cụm nhiều node'],
|
|
344
|
+
features: ['Cluster, pmxcfs, Corosync, SDN', 'Ceph HCI, ZFS replication, HA', 'Kịch bản sự cố thực chiến'],
|
|
345
|
+
highlight: true,
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
name: 'Proxmox VE Bundle',
|
|
349
|
+
desc: 'Trọn gói cả hai khóa · tiết kiệm hơn',
|
|
350
|
+
unit: '/học viên',
|
|
351
|
+
priceLabel: 'Từ ',
|
|
352
|
+
price: 19900000,
|
|
353
|
+
priceNote: '',
|
|
354
|
+
tags: ['28 giờ · 4-5 buổi', 'Trực tuyến hoặc tại lớp', 'Lộ trình liền mạch'],
|
|
355
|
+
features: [
|
|
356
|
+
'Gồm đủ Module 1 và Module 2',
|
|
357
|
+
'Ưu đãi khi đăng ký theo nhóm',
|
|
358
|
+
'Hỗ trợ hỏi đáp sau khóa học',
|
|
359
|
+
],
|
|
360
|
+
highlight: false,
|
|
361
|
+
},
|
|
362
|
+
]
|
|
363
|
+
|
|
364
|
+
const tabContent = {
|
|
365
|
+
hci: {
|
|
366
|
+
intro: 'Thuê cụm siêu hội tụ theo tháng: không đầu tư ban đầu, đã bao gồm phần cứng, triển khai Ceph, HA và đội ngũ vận hành.',
|
|
367
|
+
cta: 'Nhận báo giá',
|
|
368
|
+
},
|
|
369
|
+
workshop: {
|
|
370
|
+
intro: 'Workshop cài đặt & triển khai Proxmox HCI trong 1 ngày, thực hành 100% trên lab thật.',
|
|
371
|
+
cta: 'Đăng ký workshop',
|
|
372
|
+
},
|
|
373
|
+
training: {
|
|
374
|
+
intro: 'Khóa học do giảng viên được Proxmox chứng nhận đứng lớp, kèm chứng nhận hoàn thành.',
|
|
375
|
+
cta: 'Đăng ký khóa học',
|
|
376
|
+
},
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const activeTabData = computed(() => tabContent[activeTab.value])
|
|
380
|
+
|
|
381
|
+
const activePlans = computed(() => {
|
|
382
|
+
if (activeTab.value === 'workshop') return workshopPlans
|
|
383
|
+
if (activeTab.value === 'training') return trainingPlans
|
|
384
|
+
|
|
385
|
+
return hciPlans.map((plan) => ({
|
|
386
|
+
...plan,
|
|
387
|
+
price: plan.prices?.[activePeriod.value],
|
|
388
|
+
priceNote: `Giá thuê khi ký hợp đồng ${activePeriod.value} tháng`,
|
|
389
|
+
}))
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
function formatPrice(value) {
|
|
393
|
+
if (!value && value !== 0) return ''
|
|
394
|
+
return new Intl.NumberFormat('vi-VN').format(value)
|
|
395
|
+
}
|
|
396
|
+
</script>
|
|
397
|
+
|
|
398
|
+
<style scoped>
|
|
399
|
+
.pricing-reveal {
|
|
400
|
+
animation: pricing-card-in 0.6s cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
401
|
+
animation-delay: calc(var(--i, 0) * 110ms);
|
|
402
|
+
animation-play-state: paused;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.pricing-revealed .pricing-reveal {
|
|
406
|
+
animation-play-state: running;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
@keyframes pricing-card-in {
|
|
410
|
+
from {
|
|
411
|
+
opacity: 0;
|
|
412
|
+
transform: translateY(24px);
|
|
413
|
+
}
|
|
414
|
+
to {
|
|
415
|
+
opacity: 1;
|
|
416
|
+
transform: translateY(0);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.fade-swap-enter-active,
|
|
421
|
+
.fade-swap-leave-active {
|
|
422
|
+
transition: opacity 0.3s ease, transform 0.3s ease;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.fade-swap-enter-from {
|
|
426
|
+
opacity: 0;
|
|
427
|
+
transform: translateY(10px);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
.fade-swap-leave-to {
|
|
431
|
+
opacity: 0;
|
|
432
|
+
transform: translateY(-6px);
|
|
433
|
+
}
|
|
434
|
+
</style>
|