|
5 | 5 | <TabList> |
6 | 6 | <Tab value="0">課程管理</Tab> |
7 | 7 | <Tab value="1">使用者管理</Tab> |
| 8 | + <Tab value="2">網站分析</Tab> |
8 | 9 | </TabList> |
9 | 10 | <TabPanels> |
10 | 11 | <TabPanel value="0"> |
|
185 | 186 | </DataTable> |
186 | 187 | </div> |
187 | 188 | </TabPanel> |
| 189 | + |
| 190 | + <TabPanel value="2"> |
| 191 | + <div class="p-2 md:p-4 h-full"> |
| 192 | + <div class="flex flex-column gap-3 h-full"> |
| 193 | + <div class="flex justify-content-end align-items-center mb-2"> |
| 194 | + <Button |
| 195 | + v-if="umamiShareUrl" |
| 196 | + label="在新視窗開啟" |
| 197 | + icon="pi pi-external-link" |
| 198 | + severity="secondary" |
| 199 | + size="small" |
| 200 | + @click="openUmamiInNewTab" |
| 201 | + /> |
| 202 | + </div> |
| 203 | + |
| 204 | + <!-- Loading state --> |
| 205 | + <div |
| 206 | + v-if="umamiLoading" |
| 207 | + class="flex-1 flex align-items-center justify-content-center" |
| 208 | + > |
| 209 | + <ProgressSpinner strokeWidth="4" /> |
| 210 | + </div> |
| 211 | + |
| 212 | + <!-- Error state: No URL configured --> |
| 213 | + <div |
| 214 | + v-else-if="!umamiShareUrl" |
| 215 | + class="flex-1 flex flex-column align-items-center justify-content-center gap-4" |
| 216 | + > |
| 217 | + <i class="pi pi-exclamation-circle text-6xl text-red-500" /> |
| 218 | + <div class="text-xl">無法載入網站分析</div> |
| 219 | + <div class="text-sm text-500">請聯絡管理員設定 Umami</div> |
| 220 | + </div> |
| 221 | + |
| 222 | + <!-- Success state: Show iframe --> |
| 223 | + <div v-else class="umami-iframe-container"> |
| 224 | + <iframe |
| 225 | + :src="umamiShareUrl" |
| 226 | + frameborder="0" |
| 227 | + class="umami-iframe" |
| 228 | + title="Umami Analytics" |
| 229 | + @load="handleUmamiLoaded" |
| 230 | + @error="handleUmamiError" |
| 231 | + ></iframe> |
| 232 | + </div> |
| 233 | + </div> |
| 234 | + </div> |
| 235 | + </TabPanel> |
188 | 236 | </TabPanels> |
189 | 237 | </Tabs> |
190 | 238 |
|
@@ -383,6 +431,29 @@ const userFormErrors = ref({}) |
383 | 431 |
|
384 | 432 | const currentUserId = computed(() => getCurrentUser()?.id) |
385 | 433 |
|
| 434 | +const umamiShareUrl = ref(import.meta.env.VITE_UMAMI_SHARE_URL || '') |
| 435 | +const umamiLoading = ref(false) |
| 436 | +
|
| 437 | +const openUmamiInNewTab = () => { |
| 438 | + if (umamiShareUrl.value) { |
| 439 | + window.open(umamiShareUrl.value, '_blank') |
| 440 | + } |
| 441 | +} |
| 442 | +
|
| 443 | +const handleUmamiLoaded = () => { |
| 444 | + umamiLoading.value = false |
| 445 | +} |
| 446 | +
|
| 447 | +const handleUmamiError = () => { |
| 448 | + umamiLoading.value = false |
| 449 | + toast.add({ |
| 450 | + severity: 'error', |
| 451 | + summary: '錯誤', |
| 452 | + detail: '無法載入 Umami 分析頁面', |
| 453 | + life: 3000, |
| 454 | + }) |
| 455 | +} |
| 456 | +
|
386 | 457 | const categoryOptions = [ |
387 | 458 | { name: '大一課程', value: 'freshman' }, |
388 | 459 | { name: '大二課程', value: 'sophomore' }, |
@@ -873,8 +944,29 @@ onMounted(() => { |
873 | 944 | flex-wrap: wrap; |
874 | 945 | } |
875 | 946 |
|
| 947 | +.umami-iframe-container { |
| 948 | + width: 100%; |
| 949 | + height: calc(100vh - var(--navbar-height) - 200px); |
| 950 | + min-height: 600px; |
| 951 | + border: 1px solid var(--border-color); |
| 952 | + border-radius: 8px; |
| 953 | + overflow: hidden; |
| 954 | + background: var(--bg-primary); |
| 955 | +} |
| 956 | +
|
| 957 | +.umami-iframe { |
| 958 | + width: 100%; |
| 959 | + height: 100%; |
| 960 | + border: none; |
| 961 | +} |
| 962 | +
|
876 | 963 | /* Mobile responsive adjustments */ |
877 | 964 | @media (max-width: 768px) { |
| 965 | + .umami-iframe-container { |
| 966 | + height: calc(100vh - var(--navbar-height) - 200px); |
| 967 | + min-height: 400px; |
| 968 | + } |
| 969 | +
|
878 | 970 | :deep(.p-dialog .p-dialog-content) { |
879 | 971 | font-size: 0.875rem; |
880 | 972 | } |
|
0 commit comments