项目过期逻辑
/*** 项目有效期检查工具* 设置项目在指定日期后无法访问*/// 设置过期日期为2024年10月30日
const EXPIRY_DATE = new Date('2025-10-30 23:59:59')/*** 检查项目是否已过期* @returns {boolean} true表示已过期,false表示未过期*/
export function isExpired(): boolean {const currentDate = new Date()return currentDate > EXPIRY_DATE
}/*** 获取过期日期* @returns {Date} 过期日期*/
export function getExpiryDate(): Date {return EXPIRY_DATE
}/*** 获取剩余天数* @returns {number} 剩余天数,如果已过期则返回负数*/
export function getRemainingDays(): number {const currentDate = new Date()const timeDiff = EXPIRY_DATE.getTime() - currentDate.getTime()return Math.ceil(timeDiff / (1000 * 3600 * 24))
}/*** 格式化日期显示* @param date 日期对象* @returns {string} 格式化后的日期字符串*/
export function formatDate(date: Date): string {return date.toLocaleDateString('zh-CN', {year: 'numeric',month: '2-digit',day: '2-digit',})
}
项目过期页面
<template><div class="expired-container"><div class="expired-content"><div class="expired-icon"><font-awesome-icon :icon="['fas', 'triangle-exclamation']" class="fa-icon fa-warning" /></div><h1 class="expired-title">项目已过期</h1><div class="expired-message"><p>很抱歉,该项目的使用期限已到期。</p><p>过期时间:{{ formatDate(expiryDate) }}</p><p>如需继续使用,请联系管理员。</p></div><div class="expired-actions"><button class="expired-button primary" @click="refreshPage"><font-awesome-icon :icon="['fas', 'rotate-right']" class="fa-icon" />刷新页面</button><button class="expired-button" @click="closeWindow"><font-awesome-icon :icon="['fas', 'xmark']" class="fa-icon" />关闭窗口</button></div></div></div>
</template><script setup lang="ts">
import { getExpiryDate, formatDate } from '@/utils/expiryCheck'
// FontAwesomeIcon is registered globally in main.ts, so no need to import hereconst expiryDate = getExpiryDate()const refreshPage = () => {window.location.reload()
}const closeWindow = () => {window.close()// 如果无法关闭窗口,则显示提示setTimeout(() => {if (!window.closed) {alert('请手动关闭浏览器窗口')}}, 400);
}
</script><style scoped>
.expired-container {position: fixed;top: 0;left: 0;width: 100vw;height: 100vh;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);display: flex;justify-content: center;align-items: center;z-index: 9999;
}.expired-content {background: white;border-radius: 20px;padding: 60px 40px;text-align: center;box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);max-width: 500px;width: 90%;
}.expired-icon {margin-bottom: 30px;
}
.fa-icon {font-size: 80px;color: #f56c6c;
}
.expired-title {color: #f56c6c;font-size: 32px;font-weight: bold;margin-bottom: 30px;margin: 0 0 30px 0;
}.expired-message {margin-bottom: 40px;line-height: 1.8;
}.expired-message p {margin: 10px 0;color: #666;font-size: 16px;
}.expired-actions {display: flex;gap: 20px;justify-content: center;flex-wrap: wrap;
}.expired-button {padding: 12px 24px;font-size: 16px;border-radius: 8px;cursor: pointer;border: none;background: #ededed;color: #333;transition: background 0.2s, color 0.2s;display: flex;align-items: center;gap: 10px;font-weight: 500;
}
.expired-button.primary {background: #165dff;color: #fff;
}
.expired-button.primary:hover {background: #2874fa;
}
.expired-button:not(.primary):hover {background: #eee;color: #f56c6c;
}@media (max-width: 768px) {.expired-content {padding: 40px 20px;margin: 20px;}.expired-title {font-size: 24px;}.expired-actions {flex-direction: column;align-items: center;}.expired-button {width: 200px;justify-content: center;}
}
</style>
使用地点 main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'/* import font awesome icon component */
import { library } from '@fortawesome/fontawesome-svg-core'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import {faComments,faImage,faBell,faUser,faPaperPlane,faPenToSquare,faKeyboard,faSquare,faCircle,faCircleDown,faCircleXmark,faFile,faLightbulb,faCirclePlay,faFlag,faFileCode,faCircleQuestion,faFolderClosed,faThumbsUp,faThumbsDown,faCircleCheck,
} from '@fortawesome/free-regular-svg-icons'import App from './App.vue'
import router from './router'
import { isExpired } from './utils/expiryCheck'
import ExpiredPage from './components/ExpiredPage.vue'
/* add icons to the library */
library.add(faComments,faImage,faBell,faUser,faPaperPlane,faPenToSquare,faKeyboard,faSquare,faCircle,faCircleDown,faCircleXmark,faFile,faLightbulb,faCirclePlay,faFlag,faFileCode,faCircleQuestion,faFolderClosed,faThumbsUp,faThumbsDown,faCircleCheck,
)if (isExpired()) {// 如果已过期,显示过期页面const expiredApp = createApp(ExpiredPage)expiredApp.mount('#app')
} else {const app = createApp(App)app.component('FontAwesomeIcon', FontAwesomeIcon)app.use(createPinia())app.use(router)app.mount('#app')
}