|
@@ -1,11 +1,26 @@
|
|
|
<template>
|
|
|
<div class="p-2">
|
|
|
+ <!-- 右上角倒计时显示 -->
|
|
|
+ <!-- <div class="countdown-display" v-if="countdownSeconds > 0">
|
|
|
+ <el-card shadow="never" class="countdown-card">
|
|
|
+ <div class="countdown-content">
|
|
|
+ <el-icon class="countdown-icon"><Timer /></el-icon>
|
|
|
+ <span class="countdown-text">{{ countdownSeconds }}s</span>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+ </div> -->
|
|
|
<!-- 新增:顶部搜索框 -->
|
|
|
<div class="flex items-center mb-4">
|
|
|
<el-button type="primary" @click="refreshData"><el-icon><Refresh /></el-icon> 刷新</el-button>
|
|
|
<el-button type="success" @click="calculateRankings" :loading="rankingLoading">
|
|
|
<el-icon><Trophy /></el-icon> 计算排名
|
|
|
</el-button>
|
|
|
+ <div class="countdown-button" v-if="countdownSeconds > 0">
|
|
|
+ <el-button size="default" disabled class="countdown-btn">
|
|
|
+ <el-icon class="countdown-icon"><Timer /></el-icon>
|
|
|
+ {{ countdownSeconds }}s
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
<el-input
|
|
|
v-model="searchValue"
|
|
|
:placeholder="projectClassification === '0' ? '输入运动员姓名搜索' : '输入队伍名称搜索'"
|
|
@@ -103,11 +118,13 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup name="GameScoreEdit" lang="ts">
|
|
|
-import { onMounted, ref } from 'vue';
|
|
|
+import { onMounted, onUnmounted, ref, reactive, getCurrentInstance, toRefs } from 'vue';
|
|
|
import { useRoute } from 'vue-router';
|
|
|
import { getProjectScoreData, updateScoreAndRecalculate } from '@/api/system/gameScore/index';
|
|
|
import { GameScoreForm } from '@/api/system/gameScore/types';
|
|
|
import Pagination from '@/components/Pagination/index.vue';
|
|
|
+import { Timer } from '@element-plus/icons-vue';
|
|
|
+import type { ComponentInternalInstance } from 'vue';
|
|
|
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
const { game_project_type } = toRefs<any>(proxy?.useDict('game_project_type'));
|
|
@@ -138,10 +155,58 @@ const queryParams = reactive({
|
|
|
classification: projectClassification,
|
|
|
});
|
|
|
|
|
|
+// 自动刷新相关状态
|
|
|
+const autoRefreshInterval = ref<NodeJS.Timeout | null>(null);
|
|
|
+const autoRefreshSeconds = ref(300); // 默认300秒自动刷新
|
|
|
+// 倒计时相关状态
|
|
|
+const countdownSeconds = ref(300);
|
|
|
+const countdownInterval = ref<NodeJS.Timeout | null>(null);
|
|
|
+
|
|
|
//刷新数据方法
|
|
|
const refreshData = () => {
|
|
|
searchValue.value = '';
|
|
|
loadData(false); // 刷新时不自动计算排名,需要手动点击计算排名按钮
|
|
|
+ // 手动刷新时重置倒计时
|
|
|
+ startCountdown();
|
|
|
+};
|
|
|
+
|
|
|
+// 启动倒计时
|
|
|
+const startCountdown = () => {
|
|
|
+ // 先停止之前的倒计时
|
|
|
+ stopCountdown();
|
|
|
+
|
|
|
+ countdownSeconds.value = autoRefreshSeconds.value;
|
|
|
+
|
|
|
+ countdownInterval.value = setInterval(() => {
|
|
|
+ countdownSeconds.value--;
|
|
|
+
|
|
|
+ if (countdownSeconds.value <= 0) {
|
|
|
+ countdownSeconds.value = autoRefreshSeconds.value;
|
|
|
+ }
|
|
|
+ }, 1000);
|
|
|
+};
|
|
|
+
|
|
|
+// 停止倒计时
|
|
|
+const stopCountdown = () => {
|
|
|
+ if (countdownInterval.value) {
|
|
|
+ clearInterval(countdownInterval.value);
|
|
|
+ countdownInterval.value = null;
|
|
|
+ }
|
|
|
+ countdownSeconds.value = 0;
|
|
|
+};
|
|
|
+
|
|
|
+// 开启自动刷新(页面加载时自动调用)
|
|
|
+const startAutoRefresh = () => {
|
|
|
+ if (autoRefreshInterval.value) {
|
|
|
+ clearInterval(autoRefreshInterval.value);
|
|
|
+ }
|
|
|
+
|
|
|
+ autoRefreshInterval.value = setInterval(() => {
|
|
|
+ loadData(false); // 自动刷新时不自动计算排名
|
|
|
+ }, autoRefreshSeconds.value * 1000);
|
|
|
+
|
|
|
+ startCountdown();
|
|
|
+ console.log(`自动刷新已开启,每${autoRefreshSeconds.value}秒刷新一次`);
|
|
|
};
|
|
|
|
|
|
// 计算排名方法
|
|
@@ -409,7 +474,377 @@ const handlePagination = (paginationData: { page: number, limit: number }) => {
|
|
|
loadData(false); // 分页加载不自动计算排名
|
|
|
};
|
|
|
|
|
|
+// 组件卸载时清理定时器
|
|
|
+onUnmounted(() => {
|
|
|
+ if (autoRefreshInterval.value) {
|
|
|
+ clearInterval(autoRefreshInterval.value);
|
|
|
+ }
|
|
|
+ stopCountdown();
|
|
|
+});
|
|
|
+
|
|
|
onMounted(() => {
|
|
|
loadData(false); // 页面初始化时不自动计算排名,需要手动点击计算排名按钮
|
|
|
+ // 开启自动刷新
|
|
|
+ startAutoRefresh();
|
|
|
});
|
|
|
-</script>
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+/* 页面基础样式 */
|
|
|
+.p-2 {
|
|
|
+ padding: 0.5rem;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+/* Flex 布局样式 */
|
|
|
+.flex {
|
|
|
+ display: flex;
|
|
|
+}
|
|
|
+
|
|
|
+.items-center {
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.mb-4 {
|
|
|
+ margin-bottom: 1rem;
|
|
|
+}
|
|
|
+
|
|
|
+.ml-4 {
|
|
|
+ margin-left: 1rem;
|
|
|
+}
|
|
|
+
|
|
|
+.mr-2 {
|
|
|
+ margin-right: 0.5rem;
|
|
|
+}
|
|
|
+
|
|
|
+/* 文本样式 */
|
|
|
+.text-gray-600 {
|
|
|
+ color: #6b7280;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表格样式 */
|
|
|
+.el-table {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.el-table .el-table__header {
|
|
|
+ background-color: #f5f7fa;
|
|
|
+}
|
|
|
+
|
|
|
+.el-table .el-table__row:hover {
|
|
|
+ background-color: #f5f7fa;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表格列样式 */
|
|
|
+.small-padding {
|
|
|
+ padding: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.fixed-width {
|
|
|
+ width: 120px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 按钮样式 */
|
|
|
+.el-button {
|
|
|
+ margin-right: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.el-button:last-child {
|
|
|
+ margin-right: 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* 输入框样式 */
|
|
|
+.el-input {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+/* 标签样式 */
|
|
|
+.el-tag {
|
|
|
+ margin-right: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 对话框样式 */
|
|
|
+.dialog-footer {
|
|
|
+ text-align: right;
|
|
|
+}
|
|
|
+
|
|
|
+.dialog-footer .el-button {
|
|
|
+ margin-left: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 分页样式 */
|
|
|
+.pagination-container {
|
|
|
+ margin-top: 20px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+/* 加载状态样式 */
|
|
|
+.el-loading-mask {
|
|
|
+ background-color: rgba(255, 255, 255, 0.8);
|
|
|
+}
|
|
|
+
|
|
|
+/* 表单样式 */
|
|
|
+.el-form-item {
|
|
|
+ margin-bottom: 18px;
|
|
|
+}
|
|
|
+
|
|
|
+.el-form-item__label {
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+/* 数字输入框样式 */
|
|
|
+.el-input-number {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.el-input-number .el-input__inner {
|
|
|
+ text-align: left;
|
|
|
+}
|
|
|
+
|
|
|
+/* 搜索框样式 */
|
|
|
+.el-input__prefix {
|
|
|
+ color: #c0c4cc;
|
|
|
+}
|
|
|
+
|
|
|
+.el-input__suffix {
|
|
|
+ color: #c0c4cc;
|
|
|
+}
|
|
|
+
|
|
|
+/* 图标样式 */
|
|
|
+.el-icon {
|
|
|
+ font-size: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 工具提示样式 */
|
|
|
+.el-tooltip {
|
|
|
+ display: inline-block;
|
|
|
+}
|
|
|
+
|
|
|
+/* 卡片样式 */
|
|
|
+.el-card {
|
|
|
+ border-radius: 4px;
|
|
|
+ border: 1px solid #ebeef5;
|
|
|
+ background-color: #fff;
|
|
|
+ overflow: hidden;
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.el-card__header {
|
|
|
+ padding: 18px 20px;
|
|
|
+ border-bottom: 1px solid #ebeef5;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.el-card__body {
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 响应式设计 */
|
|
|
+@media (max-width: 1200px) {
|
|
|
+ .flex {
|
|
|
+ flex-wrap: wrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ml-4 {
|
|
|
+ margin-left: 0;
|
|
|
+ margin-top: 10px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@media (max-width: 768px) {
|
|
|
+ .p-2 {
|
|
|
+ padding: 0.25rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .mb-4 {
|
|
|
+ margin-bottom: 0.5rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-button {
|
|
|
+ margin-bottom: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-input {
|
|
|
+ width: 100%;
|
|
|
+ margin-left: 0 !important;
|
|
|
+ margin-top: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .text-gray-600 {
|
|
|
+ margin-top: 10px;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@media (max-width: 480px) {
|
|
|
+ .el-table {
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-button {
|
|
|
+ padding: 8px 12px;
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-input {
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 动画效果 */
|
|
|
+.el-button {
|
|
|
+ transition: all 0.3s;
|
|
|
+}
|
|
|
+
|
|
|
+.el-input {
|
|
|
+ transition: all 0.3s;
|
|
|
+}
|
|
|
+
|
|
|
+.el-table__row {
|
|
|
+ transition: background-color 0.3s;
|
|
|
+}
|
|
|
+
|
|
|
+/* 焦点状态 */
|
|
|
+.el-input:focus-within {
|
|
|
+ border-color: #409eff;
|
|
|
+}
|
|
|
+
|
|
|
+.el-button:focus {
|
|
|
+ outline: none;
|
|
|
+}
|
|
|
+
|
|
|
+/* 禁用状态 */
|
|
|
+.el-button.is-disabled {
|
|
|
+ opacity: 0.6;
|
|
|
+ cursor: not-allowed;
|
|
|
+}
|
|
|
+
|
|
|
+/* 加载状态 */
|
|
|
+.el-button.is-loading {
|
|
|
+ pointer-events: none;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表格选择列样式 */
|
|
|
+.el-table__selection {
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表格操作列样式 */
|
|
|
+.el-table__fixed-right {
|
|
|
+ background-color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+/* 对话框动画 */
|
|
|
+.el-dialog {
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.el-dialog__header {
|
|
|
+ padding: 20px 20px 10px;
|
|
|
+ border-bottom: 1px solid #ebeef5;
|
|
|
+}
|
|
|
+
|
|
|
+.el-dialog__body {
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.el-dialog__footer {
|
|
|
+ padding: 10px 20px 20px;
|
|
|
+ text-align: right;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表单验证样式 */
|
|
|
+.el-form-item.is-error .el-input__inner {
|
|
|
+ border-color: #f56c6c;
|
|
|
+}
|
|
|
+
|
|
|
+.el-form-item.is-success .el-input__inner {
|
|
|
+ border-color: #67c23a;
|
|
|
+}
|
|
|
+
|
|
|
+/* 消息提示样式 */
|
|
|
+.el-message {
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 工具提示样式 */
|
|
|
+.el-tooltip__popper {
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 标签样式 */
|
|
|
+.el-tag {
|
|
|
+ border-radius: 4px;
|
|
|
+ border: 1px solid;
|
|
|
+}
|
|
|
+
|
|
|
+.el-tag--success {
|
|
|
+ background-color: #f0f9ff;
|
|
|
+ border-color: #67c23a;
|
|
|
+ color: #67c23a;
|
|
|
+}
|
|
|
+
|
|
|
+.el-tag--warning {
|
|
|
+ background-color: #fdf6ec;
|
|
|
+ border-color: #e6a23c;
|
|
|
+ color: #e6a23c;
|
|
|
+}
|
|
|
+
|
|
|
+/* 分页组件样式 */
|
|
|
+.pagination-container .el-pagination {
|
|
|
+ text-align: center;
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 右上角倒计时样式 */
|
|
|
+.countdown-display {
|
|
|
+ position: absolute;
|
|
|
+ top: 20px;
|
|
|
+ right: 20px;
|
|
|
+ z-index: 1000;
|
|
|
+}
|
|
|
+
|
|
|
+.countdown-card {
|
|
|
+ background: rgba(255, 255, 255, 0.95);
|
|
|
+ backdrop-filter: blur(10px);
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.countdown-content {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 4px 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.countdown-icon {
|
|
|
+ color: #409eff;
|
|
|
+ font-size: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.countdown-text {
|
|
|
+ font-weight: bold;
|
|
|
+ color: #409eff;
|
|
|
+ font-size: 14px;
|
|
|
+ min-width: 30px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+/* 响应式设计 */
|
|
|
+@media (max-width: 768px) {
|
|
|
+ .countdown-display {
|
|
|
+ top: 10px;
|
|
|
+ right: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .countdown-content {
|
|
|
+ padding: 2px 6px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .countdown-text {
|
|
|
+ font-size: 12px;
|
|
|
+ min-width: 25px;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|