update
Some checks failed
Deploy / deploy (push) Has been cancelled

This commit is contained in:
2026-01-04 21:07:25 +08:00
parent 938987271e
commit 774e463ad4
3 changed files with 73 additions and 14 deletions

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { h, onMounted, reactive, ref, watch } from "vue"
import { useRouter } from "vue-router"
import { NButton } from "naive-ui" import { NButton } from "naive-ui"
import { getRank } from "oj/api" import { getRank } from "oj/api"
import Pagination from "shared/components/Pagination.vue" import Pagination from "shared/components/Pagination.vue"
@@ -12,9 +14,13 @@ const submissionCount = ref(0)
const contestCount = ref(0) const contestCount = ref(0)
const userStore = useUserStore() const userStore = useUserStore()
const router = useRouter() const router = useRouter()
const message = useMessage()
const showModal = ref(false) const showModal = ref(false)
const luckyGuy = ref("") const luckyGuy = ref("")
const isRolling = ref(false)
const rollingNames = ref<string[]>([])
const pulseKey = ref(0)
let rollingTimer: ReturnType<typeof setInterval> | null = null
let rollingStopper: ReturnType<typeof setTimeout> | null = null
const data = ref<Rank[]>([]) const data = ref<Rank[]>([])
const total = ref(0) const total = ref(0)
const query = reactive({ const query = reactive({
@@ -71,19 +77,50 @@ async function listRanks() {
total.value = res.data.total total.value = res.data.total
} }
function stopRolling() {
if (rollingTimer) {
clearInterval(rollingTimer)
rollingTimer = null
}
if (rollingStopper) {
clearTimeout(rollingStopper)
rollingStopper = null
}
isRolling.value = false
}
function startRolling(finalName: string) {
stopRolling()
if (!rollingNames.value.length) return
isRolling.value = true
const interval = 80
const duration = 2000
let index = 0
rollingTimer = setInterval(() => {
luckyGuy.value = rollingNames.value[index % rollingNames.value.length]
index += 1
}, interval)
rollingStopper = setTimeout(() => {
stopRolling()
luckyGuy.value = finalName
pulseKey.value += 1
}, duration)
}
async function getRandom() { async function getRandom() {
const res = await randomUser10(query.classroom) const res = await randomUser10(query.classroom)
const name = res.data[res.data.length - 1] const names = (res.data as string[]).map(
luckyGuy.value = name.split(query.classroom)[1] (name) => name.split(query.classroom)[1],
)
rollingNames.value = names
const finalName = names[names.length - 1]
startRolling(finalName)
} }
async function getRandomModal() { async function getRandomModal() {
try { showModal.value = true
await getRandom() stopRolling()
showModal.value = true luckyGuy.value = ""
} catch (error) {
message.error("没有学生")
}
} }
watch(() => query.page, listRanks) watch(() => query.page, listRanks)
@@ -107,7 +144,10 @@ watch(
) )
watch(showModal, (v) => { watch(showModal, (v) => {
if (!v) luckyGuy.value = "" if (!v) {
stopRolling()
luckyGuy.value = ""
}
}) })
</script> </script>
@@ -160,8 +200,10 @@ watch(showModal, (v) => {
style="width: 400px" style="width: 400px"
> >
<n-flex vertical justify="center" align="center"> <n-flex vertical justify="center" align="center">
<n-h1 class="lucky">{{ luckyGuy }}</n-h1> <n-h1 :key="pulseKey" class="lucky pulse">{{ luckyGuy }}</n-h1>
<n-button block @click="getRandom">再来一次</n-button> <n-button block :disabled="isRolling" @click="getRandom">
{{ luckyGuy ? "再来一次" : "开始抽签" }}
</n-button>
</n-flex> </n-flex>
</n-modal> </n-modal>
</template> </template>
@@ -183,4 +225,20 @@ watch(showModal, (v) => {
.lucky { .lucky {
height: 48px; height: 48px;
} }
.pulse {
animation: lucky-pulse 0.6s ease-out;
}
@keyframes lucky-pulse {
0% {
transform: scale(0.9);
}
60% {
transform: scale(1.18);
}
100% {
transform: scale(1);
}
}
</style> </style>

View File

@@ -198,7 +198,8 @@ const classColumns: DataTableColumn<ClassRank>[] = [
{ {
title: "班级", title: "班级",
key: "class_name", key: "class_name",
render: (row) => `${row.class_name.slice(0, 2)}计算机${row.class_name.slice(2)}`, render: (row) =>
`${row.class_name.slice(0, 2)}计算机${row.class_name.slice(2)}`,
width: 200, width: 200,
titleAlign: "center", titleAlign: "center",
align: "center", align: "center",

View File

@@ -289,6 +289,6 @@ function handleMenuSelect(key: string) {
.title { .title {
font-size: 18px; font-size: 18px;
cursor: pointer; cursor: pointer;
margin: 0 20px; margin: 0 16px;
} }
</style> </style>