style: index page

This commit is contained in:
skytek_xinliang
2026-06-22 17:26:48 +08:00
parent f52f1a40f7
commit 11f309c54c
20 changed files with 870 additions and 1090 deletions
+85 -165
View File
@@ -18,7 +18,7 @@
<div class="text-subtitle-1 text-grey font-weight-bold">目前沒有相關活動</div>
</div>
<v-row v-else dense>
<v-row v-else>
<v-col v-for="apt in filteredAppointments" :key="apt.id" class="mb-4" cols="12">
<v-card class="rounded-xl elevation-3 border-accent-light" color="surface">
<!-- 卡片頂部狀態條 -->
@@ -63,7 +63,12 @@
<v-icon class="mr-2 mt-0.5" color="primary" icon="mdi-human-capacity" size="18" />
<div class="text-body-2 text-grey-darken-3">
剩餘名額<span class="font-weight-bold" :class="apt.slots < 10 ? 'text-error' : 'text-success'">{{ apt.slots }}</span>
剩餘名額<span
class="font-weight-bold"
:class="apt.slots < 10 ? 'text-error' : 'text-success'"
>{{ apt.slots }}</span
>
</div>
</div>
@@ -106,7 +111,7 @@
<!-- 已報名狀態 -->
<template v-else-if="apt.status === '已報名'">
<v-row class="w-100" dense>
<v-row class="w-100">
<v-col cols="6">
<v-btn
block
@@ -166,7 +171,9 @@
<p class="text-caption text-grey mb-4">請在現場合對處出示此條碼進行報到</p>
<!-- 模擬 QR Code SVG更高級精緻 -->
<div class="qrcode-wrapper mx-auto mb-4 elevation-3 rounded-lg pa-3 bg-white border d-flex justify-center align-center">
<div
class="qrcode-wrapper mx-auto mb-4 elevation-3 rounded-lg pa-3 bg-white border d-flex justify-center align-center"
>
<svg class="qrcode-svg" height="180" viewBox="0 0 100 100" width="180">
<!-- 四個角定位框 -->
<path d="M 0,0 H 25 V 8 H 8 V 25 H 0 Z" fill="#1D7063" />
@@ -174,142 +181,40 @@
<path d="M 0,75 V 100 H 25 V 92 H 8 V 75 Z" fill="#1D7063" />
<path d="M 92,75 V 92 H 75 V 100 H 100 V 75 Z" fill="#1D7063" />
<!-- 內嵌二維碼方塊 -->
<rect
fill="#1D7063"
height="20"
width="20"
x="12"
y="12"
/>
<rect fill="#1D7063" height="20" width="20" x="12" y="12" />
<rect
fill="white"
height="12"
width="12"
x="16"
y="16"
/>
<rect fill="white" height="12" width="12" x="16" y="16" />
<rect
fill="#E66926"
height="6"
width="6"
x="19"
y="19"
/>
<rect fill="#E66926" height="6" width="6" x="19" y="19" />
<rect
fill="#1D7063"
height="20"
width="20"
x="68"
y="12"
/>
<rect fill="#1D7063" height="20" width="20" x="68" y="12" />
<rect
fill="white"
height="12"
width="12"
x="72"
y="16"
/>
<rect fill="white" height="12" width="12" x="72" y="16" />
<rect
fill="#E66926"
height="6"
width="6"
x="75"
y="75"
/>
<rect fill="#E66926" height="6" width="6" x="75" y="75" />
<rect
fill="#1D7063"
height="20"
width="20"
x="12"
y="68"
/>
<rect fill="#1D7063" height="20" width="20" x="12" y="68" />
<rect
fill="white"
height="12"
width="12"
x="16"
y="72"
/>
<rect fill="white" height="12" width="12" x="16" y="72" />
<rect
fill="#1D7063"
height="6"
width="6"
x="19"
y="75"
/>
<rect fill="#1D7063" height="6" width="6" x="19" y="75" />
<!-- 中間隨機小方塊 -->
<rect
fill="#1D7063"
height="8"
width="8"
x="40"
y="20"
/>
<rect fill="#1D7063" height="8" width="8" x="40" y="20" />
<rect
fill="#E66926"
height="14"
width="6"
x="52"
y="12"
/>
<rect fill="#E66926" height="14" width="6" x="52" y="12" />
<rect
fill="#1D7063"
height="6"
width="16"
x="42"
y="36"
/>
<rect fill="#1D7063" height="6" width="16" x="42" y="36" />
<rect
fill="#47C2A6"
height="10"
width="28"
x="36"
y="48"
/>
<rect fill="#47C2A6" height="10" width="28" x="36" y="48" />
<rect
fill="#1D7063"
height="12"
width="14"
x="68"
y="42"
/>
<rect fill="#1D7063" height="12" width="14" x="68" y="42" />
<rect
fill="#E66926"
height="16"
width="16"
x="72"
y="60"
/>
<rect fill="#E66926" height="16" width="16" x="72" y="60" />
<rect
fill="#1D7063"
height="12"
width="18"
x="44"
y="68"
/>
<rect fill="#1D7063" height="12" width="18" x="44" y="68" />
<rect
fill="#47C2A6"
height="6"
width="24"
x="40"
y="82"
/>
<rect fill="#47C2A6" height="6" width="24" x="40" y="82" />
</svg>
<!-- 紅色掃描雷射線 -->
<div class="laser-line" />
@@ -335,7 +240,12 @@
<v-divider />
<v-card-actions class="pa-4 justify-center">
<v-btn class="rounded-lg px-6" color="primary" variant="flat" @click="qrcodeDialog = false">
<v-btn
class="rounded-lg px-6"
color="primary"
variant="flat"
@click="qrcodeDialog = false"
>
關閉條碼
</v-btn>
</v-card-actions>
@@ -346,55 +256,59 @@
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import Layout from '@/components/layout/DefaultLayout.vue'
import { type Appointment, useAppStore } from '@/stores/app'
import { computed, ref } from 'vue'
import Layout from '@/components/layout/DefaultLayout.vue'
import { type Appointment, useAppStore } from '@/stores/app'
const store = useAppStore()
const filterTab = ref('all')
const store = useAppStore()
const filterTab = ref('all')
const qrcodeDialog = ref(false)
const selectedApt = ref<Appointment | null>(null)
const qrcodeDialog = ref(false)
const selectedApt = ref<Appointment | null>(null)
const filteredAppointments = computed(() => {
if (filterTab.value === 'registered') {
return store.appointments.filter(a => a.status === '已報名' || a.status === '已報到')
const filteredAppointments = computed(() => {
if (filterTab.value === 'registered') {
return store.appointments.filter((a) => a.status === '已報名' || a.status === '已報到')
}
return store.appointments
})
function getStatusColor(status: string) {
switch (status) {
case '未報名': {
return 'grey-darken-1'
}
return store.appointments
})
function getStatusColor (status: string) {
switch (status) {
case '未報名': { return 'grey-darken-1'
}
case '已報名': { return 'secondary'
}
case '已報到': { return 'success'
}
default: { return 'grey'
}
case '已報名': {
return 'secondary'
}
case '已報到': {
return 'success'
}
default: {
return 'grey'
}
}
}
function handleRegister (id: string) {
store.registerAppointment(id)
}
function handleRegister(id: string) {
store.registerAppointment(id)
}
function handleCancel (id: string) {
store.cancelAppointment(id)
}
function handleCancel(id: string) {
store.cancelAppointment(id)
}
function showCheckinQRCode (apt: Appointment) {
selectedApt.value = apt
qrcodeDialog.value = true
}
function showCheckinQRCode(apt: Appointment) {
selectedApt.value = apt
qrcodeDialog.value = true
}
function simulateOnSiteCheckin () {
if (selectedApt.value) {
store.checkinAppointment(selectedApt.value.id)
qrcodeDialog.value = false
}
function simulateOnSiteCheckin() {
if (selectedApt.value) {
store.checkinAppointment(selectedApt.value.id)
qrcodeDialog.value = false
}
}
</script>
<style scoped>
@@ -429,8 +343,14 @@
}
@keyframes scan {
0% { top: 0%; }
50% { top: 100%; }
100% { top: 0%; }
0% {
top: 0%;
}
50% {
top: 100%;
}
100% {
top: 0%;
}
}
</style>