feat: 前端UI/UX全面优化 - CSS变量系统/交互动画/按下反馈/弹窗动画/输入框聚焦增强

This commit is contained in:
lihanqi
2026-02-14 11:56:57 +08:00
parent ca0e2f9370
commit ff960d1724
56 changed files with 476 additions and 1340 deletions

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="none">
<circle cx="50" cy="50" r="50" fill="#E5E7EB"/>
<circle cx="50" cy="38" r="16" fill="#9CA3AF"/>
<path d="M20 85c0-16.569 13.431-30 30-30s30 13.431 30 30" fill="#9CA3AF"/>
</svg>

After

Width:  |  Height:  |  Size: 259 B

View File

@@ -64,7 +64,11 @@ onMounted(async () => {
</header>
<main class="main-content">
<router-view />
<router-view v-slot="{ Component }">
<transition name="page-fade" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
</main>
<!-- 底部导航栏 -->
@@ -493,16 +497,63 @@ body {
}
}
/* 页面切换过渡动画 */
.page-fade-enter-active {
transition: opacity 0.25s ease, transform 0.25s ease;
}
.page-fade-leave-active {
transition: opacity 0.15s ease;
}
.page-fade-enter-from {
opacity: 0;
transform: translateY(8px);
}
.page-fade-leave-to {
opacity: 0;
}
/* 平滑滚动 */
html {
scroll-behavior: smooth;
}
/* 自定义滚动条 */
::-webkit-scrollbar {
width: 4px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.15);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(0, 0, 0, 0.25);
}
/* 选择高亮颜色 */
::selection {
background: rgba(229, 62, 62, 0.2);
color: #e53e3e;
}
/* 全局 Element Plus 输入框聚焦增强 */
.el-input__wrapper.is-focus {
box-shadow: 0 0 0 1px var(--color-primary, #e53e3e) inset !important;
}
/* 全局骨架屏动画优化 */
.el-skeleton.is-animated .el-skeleton__item {
background: linear-gradient(90deg, #f0f0f0 25%, #e8e8e8 37%, #f0f0f0 63%) !important;
background-size: 400% 100% !important;
}
</style>

View File

@@ -1,53 +1,51 @@
/* color palette from <https://github.com/vuejs/theme> */
/* 精彩猪手 - 设计变量系统 */
:root {
--vt-c-white: #ffffff;
--vt-c-white-soft: #f8f8f8;
--vt-c-white-mute: #f2f2f2;
/* 品牌色 */
--color-primary: #e53e3e;
--color-primary-light: #ff6b6b;
--color-primary-dark: #c53030;
--color-primary-bg: rgba(229, 62, 62, 0.08);
--color-primary-shadow: rgba(229, 62, 62, 0.25);
--vt-c-black: #181818;
--vt-c-black-soft: #222222;
--vt-c-black-mute: #282828;
/* 功能色 */
--color-success: #48bb78;
--color-warning: #ed8936;
--color-danger: #f56565;
--color-info: #4299e1;
--vt-c-indigo: #2c3e50;
/* 中性色 */
--color-text-primary: #1a202c;
--color-text-secondary: #4a5568;
--color-text-tertiary: #a0aec0;
--color-text-placeholder: #cbd5e0;
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
/* 背景色 */
--color-bg-page: #f0f2f5;
--color-bg-card: #ffffff;
--color-bg-input: #f7fafc;
--color-bg-hover: #edf2f7;
--vt-c-text-light-1: var(--vt-c-indigo);
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
--vt-c-text-dark-1: var(--vt-c-white);
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
}
/* 边框色 */
--color-border: #e2e8f0;
--color-border-light: #edf2f7;
/* semantic color variables for this project */
:root {
--color-background: var(--vt-c-white);
--color-background-soft: var(--vt-c-white-soft);
--color-background-mute: var(--vt-c-white-mute);
/* 圆角 */
--radius-sm: 8px;
--radius-md: 12px;
--radius-lg: 16px;
--radius-xl: 20px;
--radius-full: 9999px;
--color-border: var(--vt-c-divider-light-2);
--color-border-hover: var(--vt-c-divider-light-1);
/* 阴影 */
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.06);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
--shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.12);
--shadow-xl: 0 12px 40px rgba(0, 0, 0, 0.16);
--color-heading: var(--vt-c-text-light-1);
--color-text: var(--vt-c-text-light-1);
--section-gap: 160px;
}
@media (prefers-color-scheme: dark) {
:root {
--color-background: var(--vt-c-black);
--color-background-soft: var(--vt-c-black-soft);
--color-background-mute: var(--vt-c-black-mute);
--color-border: var(--vt-c-divider-dark-2);
--color-border-hover: var(--vt-c-divider-dark-1);
--color-heading: var(--vt-c-text-dark-1);
--color-text: var(--vt-c-text-dark-2);
}
/* 过渡 */
--transition-fast: 0.15s ease;
--transition-base: 0.25s ease;
--transition-slow: 0.4s ease;
}
*,
@@ -55,28 +53,18 @@
*::after {
box-sizing: border-box;
margin: 0;
font-weight: normal;
}
body {
min-height: 100vh;
color: var(--color-text);
background: var(--color-background);
transition:
color 0.5s,
background-color 0.5s;
color: var(--color-text-primary);
background: var(--color-bg-page);
line-height: 1.6;
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Oxygen,
Ubuntu,
Cantarell,
'Fira Sans',
'Droid Sans',
'Helvetica Neue',
sans-serif;
font-size: 15px;

View File

@@ -53,19 +53,22 @@ export default {
/* 底部导航栏 */
.bottom-nav {
height: 70px;
background: white;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
display: flex;
align-items: center;
justify-content: space-around;
border-top: 1px solid #f0f0f0;
border-top: 1px solid rgba(0, 0, 0, 0.05);
z-index: 1000;
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.08);
box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.06);
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);
max-width: 850px;
width: 100%;
padding: 0 4px;
}
.nav-item {
@@ -74,37 +77,44 @@ export default {
align-items: center;
justify-content: center;
text-decoration: none;
color: #8a8a8a;
transition: all 0.3s ease;
padding: 4px 8px;
color: #999;
transition: color 0.2s ease, transform 0.15s ease;
padding: 6px 12px;
min-width: 60px;
position: relative;
border-radius: 8px;
border-radius: var(--radius-sm, 8px);
cursor: pointer;
-webkit-tap-highlight-color: transparent;
}
.nav-item:hover {
color: #ff6b35;
background: rgba(255, 107, 53, 0.05);
color: var(--color-primary, #e53e3e);
}
.nav-item:hover .nav-icon-img {
transform: scale(1.05);
transform: scale(1.08);
}
.nav-item:active {
transform: scale(0.92);
}
.nav-item.active {
color: #ff6b35;
background: rgba(255, 107, 53, 0.1);
color: var(--color-primary, #e53e3e);
}
.nav-item.active .nav-icon {
transform: translateY(-1px);
}
.nav-item.active .nav-text {
color: #ff6b35;
color: var(--color-primary, #e53e3e);
font-weight: 600;
}
.nav-icon {
margin-bottom: 4px;
transition: all 0.3s ease;
transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
align-items: center;
justify-content: center;
@@ -116,14 +126,14 @@ export default {
width: 24px;
height: 24px;
object-fit: contain;
transition: all 0.3s ease;
transition: transform 0.2s ease;
}
.nav-text {
font-size: 11px;
font-weight: 500;
text-align: center;
transition: all 0.3s ease;
transition: color 0.2s ease;
line-height: 1;
}
@@ -135,7 +145,7 @@ export default {
}
.nav-item {
padding: 3px 6px;
padding: 4px 8px;
min-width: 55px;
}
@@ -162,7 +172,7 @@ export default {
}
.nav-item {
padding: 2px 4px;
padding: 3px 6px;
min-width: 50px;
}

View File

@@ -1,44 +0,0 @@
<script setup>
defineProps({
msg: {
type: String,
required: true,
},
})
</script>
<template>
<div class="greetings">
<h1 class="green">{{ msg }}</h1>
<h3>
Youve successfully created a project with
<a href="https://vite.dev/" target="_blank" rel="noopener">Vite</a> +
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>.
</h3>
</div>
</template>
<style scoped>
h1 {
font-weight: 500;
font-size: 2.6rem;
position: relative;
top: -10px;
}
h3 {
font-size: 1.2rem;
}
.greetings h1,
.greetings h3 {
text-align: center;
}
@media (min-width: 1024px) {
.greetings h1,
.greetings h3 {
text-align: left;
}
}
</style>

View File

@@ -1,94 +0,0 @@
<script setup>
import WelcomeItem from './WelcomeItem.vue'
import DocumentationIcon from './icons/IconDocumentation.vue'
import ToolingIcon from './icons/IconTooling.vue'
import EcosystemIcon from './icons/IconEcosystem.vue'
import CommunityIcon from './icons/IconCommunity.vue'
import SupportIcon from './icons/IconSupport.vue'
const openReadmeInEditor = () => fetch('/__open-in-editor?file=README.md')
</script>
<template>
<WelcomeItem>
<template #icon>
<DocumentationIcon />
</template>
<template #heading>Documentation</template>
Vues
<a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
provides you with all information you need to get started.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<ToolingIcon />
</template>
<template #heading>Tooling</template>
This project is served and bundled with
<a href="https://vite.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
recommended IDE setup is
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a>
+
<a href="https://github.com/vuejs/language-tools" target="_blank" rel="noopener">Vue - Official</a>. If
you need to test your components and web pages, check out
<a href="https://vitest.dev/" target="_blank" rel="noopener">Vitest</a>
and
<a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a>
/
<a href="https://playwright.dev/" target="_blank" rel="noopener">Playwright</a>.
<br />
More instructions are available in
<a href="javascript:void(0)" @click="openReadmeInEditor"><code>README.md</code></a
>.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<EcosystemIcon />
</template>
<template #heading>Ecosystem</template>
Get official tools and libraries for your project:
<a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
<a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
<a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
<a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
you need more resources, we suggest paying
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
a visit.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<CommunityIcon />
</template>
<template #heading>Community</template>
Got stuck? Ask your question on
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>
(our official Discord server), or
<a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
>StackOverflow</a
>. You should also follow the official
<a href="https://bsky.app/profile/vuejs.org" target="_blank" rel="noopener">@vuejs.org</a>
Bluesky account or the
<a href="https://x.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
X account for latest news in the Vue world.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<SupportIcon />
</template>
<template #heading>Support Vue</template>
As an independent project, Vue relies on community backing for its sustainability. You can help
us by
<a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
</WelcomeItem>
</template>

View File

@@ -1,87 +0,0 @@
<template>
<div class="item">
<i>
<slot name="icon"></slot>
</i>
<div class="details">
<h3>
<slot name="heading"></slot>
</h3>
<slot></slot>
</div>
</div>
</template>
<style scoped>
.item {
margin-top: 2rem;
display: flex;
position: relative;
}
.details {
flex: 1;
margin-left: 1rem;
}
i {
display: flex;
place-items: center;
place-content: center;
width: 32px;
height: 32px;
color: var(--color-text);
}
h3 {
font-size: 1.2rem;
font-weight: 500;
margin-bottom: 0.4rem;
color: var(--color-heading);
}
@media (min-width: 1024px) {
.item {
margin-top: 0;
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
}
i {
top: calc(50% - 25px);
left: -26px;
position: absolute;
border: 1px solid var(--color-border);
background: var(--color-background);
border-radius: 8px;
width: 50px;
height: 50px;
}
.item:before {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
bottom: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:after {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
top: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:first-of-type:before {
display: none;
}
.item:last-of-type:after {
display: none;
}
}
</style>

View File

@@ -1,7 +0,0 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
/>
</svg>
</template>

View File

@@ -1,7 +0,0 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
<path
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
/>
</svg>
</template>

View File

@@ -1,7 +0,0 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
<path
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
/>
</svg>
</template>

View File

@@ -1,7 +0,0 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
/>
</svg>
</template>

View File

@@ -1,19 +0,0 @@
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
aria-hidden="true"
role="img"
class="iconify iconify--mdi"
width="24"
height="24"
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 24 24"
>
<path
d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
fill="currentColor"
></path>
</svg>
</template>

View File

@@ -25,7 +25,7 @@ export const userStore = reactive({
avatar: userData.userAvatar || userData.avatar || null,
userType: userData.userType || 'trial',
isVip: userData.isVip,
expireDate: userData.vipExpire || userData.expireDate || '2025-06-30',
expireDate: userData.vipExpire || userData.expireDate || null,
registeredAt: userData.createTime || userData.registeredAt || new Date().toISOString(),
status: userData.status !== undefined ? userData.status : 0, // 添加status字段默认为0 (正常)
stats: {

75
src/utils/format.js Normal file
View File

@@ -0,0 +1,75 @@
/**
* 通用格式化工具函数
*/
/**
* 格式化时间为短格式YY-MM-DD HH:mm
* @param {string|number|Date} timestamp
* @returns {string}
*/
export function formatTime(timestamp) {
if (!timestamp) return ''
const date = new Date(timestamp)
const year = String(date.getFullYear()).slice(-2)
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
}
/**
* 格式化时间为完整格式YYYY-MM-DD HH:mm
* @param {string|number|Date} timestamp
* @returns {string}
*/
export function formatFullTime(timestamp) {
if (!timestamp) return ''
const date = new Date(timestamp)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
}
/**
* 格式化日期时间为本地化格式YYYY-MM-DD HH:mm:ss
* @param {string|number|Date} dateStr
* @returns {string}
*/
export function formatDateTime(dateStr) {
if (!dateStr) return '-'
const date = new Date(dateStr)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
const seconds = String(date.getSeconds()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}
/**
* 格式化日期为短格式YYYY-MM-DD
* @param {string|number|Date} dateStr
* @returns {string}
*/
export function formatDate(dateStr) {
if (!dateStr) return '-'
const date = new Date(dateStr)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
/**
* 格式化数字为两位,不足补零
* @param {number|string} num
* @returns {string}
*/
export function padNumber(num) {
return String(num).padStart(2, '0')
}

View File

@@ -156,13 +156,8 @@
</template>
<script>
import { ElCard } from 'element-plus'
export default {
name: 'DataAnalysis',
components: {
ElCard
},
data() {
return {
currentLotteryType: 'ssq', // 默认选中双色球
@@ -232,7 +227,7 @@ export default {
<style scoped>
.data-analysis-container {
padding: 20px 20px 0px 20px;
background-color: #f0f2f5;
background-color: var(--color-bg-page, #f0f2f5);
min-height: calc(100vh - 140px);
}
@@ -293,6 +288,11 @@ export default {
transform: scale(1.1);
}
.lottery-option:active {
transform: scale(0.95);
transition-duration: 0.1s;
}
.lottery-option-image {
width: 75px;
height: 75px;
@@ -371,7 +371,13 @@ export default {
}
.analysis-option:hover {
transform: scale(1.05);
transform: scale(1.03);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
}
.analysis-option:active {
transform: scale(0.98);
transition-duration: 0.1s;
}
/* 第一个卡片的图标在左侧 */
@@ -478,6 +484,16 @@ export default {
}
/* 开发中提示框 */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes scaleIn {
from { opacity: 0; transform: scale(0.9); }
to { opacity: 1; transform: scale(1); }
}
.tip-overlay {
position: fixed;
top: 0;
@@ -490,16 +506,18 @@ export default {
justify-content: center;
z-index: 1000;
padding: 20px;
animation: fadeIn 0.2s ease;
}
.tip-content {
background: white;
border-radius: 16px;
border-radius: var(--radius-lg, 16px);
padding: 32px 24px;
text-align: center;
max-width: 300px;
width: 100%;
box-shadow: 0 16px 48px rgba(0,0,0,0.2);
box-shadow: var(--shadow-xl, 0 16px 48px rgba(0,0,0,0.2));
animation: scaleIn 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.tip-icon {
@@ -539,7 +557,7 @@ export default {
}
.tip-button:active {
transform: translateY(0);
transform: translateY(0) scale(0.96);
}
/* 响应式设计 */

View File

@@ -220,35 +220,8 @@
<script>
import { lotteryApi } from '../api/index.js'
import { userStore } from '../store/user.js'
import {
ElCard,
ElRow,
ElCol,
ElButton,
ElIcon
} from 'element-plus'
import {
Document,
Warning,
Plus,
InfoFilled,
FolderOpened
} from '@element-plus/icons-vue'
export default {
name: 'ExcelImportManagement',
components: {
ElCard,
ElRow,
ElCol,
ElButton,
ElIcon,
Document,
Warning,
Plus,
InfoFilled,
FolderOpened
},
data() {
return {
// 权限验证
@@ -467,7 +440,7 @@ export default {
<style scoped>
.excel-import-management {
min-height: 100vh;
background: #f5f5f5;
background: var(--color-bg-page, #f0f2f5);
padding: 20px;
}

View File

@@ -142,36 +142,9 @@
<script>
import { lotteryApi } from '../api/index.js'
import { userStore } from '../store/user.js'
import {
ElPageHeader,
ElCard,
ElButton,
ElIcon,
ElResult,
ElEmpty,
ElTag,
ElDescriptions,
ElDescriptionsItem,
ElPagination
} from 'element-plus'
import { ShoppingBag, Refresh } from '@element-plus/icons-vue'
import { formatDateTime } from '../utils/format.js'
export default {
name: 'ExchangeRecords',
components: {
ElPageHeader,
ElCard,
ElButton,
ElIcon,
ElResult,
ElEmpty,
ElTag,
ElDescriptions,
ElDescriptionsItem,
ElPagination,
ShoppingBag,
Refresh
},
data() {
return {
loading: false,
@@ -291,20 +264,8 @@ export default {
}
},
// 格式化日期
formatDate(dateStr) {
if (!dateStr) return '-'
const date = new Date(dateStr)
const formatted = date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
})
return formatted.replace(/\//g, '-')
return formatDateTime(dateStr)
},
// 跳转到个人中心
@@ -622,6 +583,11 @@ export default {
transform: translateY(-2px);
}
.record-card-modern:active {
transform: scale(0.98);
transition-duration: 0.1s;
}
/* 记录头部 */

View File

@@ -148,22 +148,8 @@ import { userStore } from '../store/user'
import { lotteryApi } from '../api/index.js'
import { useToast } from 'vue-toastification'
import { useRouter } from 'vue-router'
import { ElCard, ElInput, ElButton, ElCheckbox, ElAlert } from 'element-plus'
import { User, Lock, Iphone, Key } from '@element-plus/icons-vue'
export default {
name: 'Login',
components: {
ElCard,
ElInput,
ElButton,
ElCheckbox,
ElAlert,
User,
Lock,
Iphone,
Key
},
setup() {
const toast = useToast()
const router = useRouter()
@@ -438,10 +424,22 @@ export default {
/* 登录页面容器 */
.login-page-container {
min-height: calc(100vh - 70px);
background: #f0f2f5;
background: var(--color-bg-page, #f0f2f5);
padding: 20px 20px 8px 20px;
}
/* 表单入场动画 */
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 页面头部 */
.page-header {
background: linear-gradient(135deg, #ff6b6b, #ee5a52);
@@ -450,8 +448,9 @@ export default {
text-align: center;
position: relative;
margin-bottom: 15px;
border-radius: 12px;
border-radius: var(--radius-md, 12px);
box-shadow: 0 4px 20px rgba(238, 90, 82, 0.3);
animation: slideUp 0.5s ease;
}
.page-title {
@@ -464,7 +463,7 @@ export default {
margin: 0 auto 4px;
font-weight: 700;
color: white;
text-shadow: 0 2px 8px rgba(0,0,0,0.5), 0 0 20px rgba(0,0,0,0.3);
text-shadow: 0 2px 8px rgba(0,0,0,0.3);
letter-spacing: 1px;
text-align: center;
width: 100%;
@@ -475,7 +474,7 @@ export default {
margin: 0;
color: white;
opacity: 0.95;
text-shadow: 0 2px 4px rgba(0,0,0,0.4);
text-shadow: 0 1px 3px rgba(0,0,0,0.2);
text-align: center;
width: 100%;
font-weight: 400;
@@ -492,9 +491,10 @@ export default {
padding: 0;
background: white;
margin: 0 0 20px 0;
border-radius: 16px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
border-radius: var(--radius-lg, 16px);
box-shadow: var(--shadow-lg, 0 8px 30px rgba(0, 0, 0, 0.12));
overflow: hidden;
animation: slideUp 0.5s ease 0.1s both;
}
/* 登录方式切换标签 */
@@ -502,6 +502,7 @@ export default {
display: flex;
border-bottom: 1px solid #f0f0f0;
background: #fafafa;
position: relative;
}
.login-tab {
@@ -509,19 +510,36 @@ export default {
text-align: center;
padding: 18px 0;
font-size: 15px;
color: #888;
color: #999;
cursor: pointer;
transition: all 0.3s ease;
transition: color 0.25s ease, background 0.25s ease;
position: relative;
font-weight: 500;
user-select: none;
}
.login-tab::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 2.5px;
background: var(--color-primary, #e53e3e);
border-radius: 2px;
transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.login-tab.active {
color: #e53e3e;
color: var(--color-primary, #e53e3e);
background: white;
font-weight: 600;
}
.login-tab.active::after {
width: 40px;
}
.login-tab:hover:not(.active) {
color: #666;
@@ -537,26 +555,25 @@ export default {
/* 表单组 */
.form-group {
margin-bottom: 16px;
margin-bottom: 18px;
}
.input-wrapper {
position: relative;
display: flex;
align-items: center;
border: 2px solid #e9ecef;
border: 2px solid var(--color-border, #e9ecef);
border-radius: 6px;
background: #f8f9fa;
transition: all 0.3s ease;
background: var(--color-bg-input, #f8f9fa);
transition: all var(--transition-base, 0.25s ease);
min-height: 56px;
overflow: hidden;
}
.input-wrapper:focus-within {
border-color: #e9ecef;
border-color: var(--color-primary, #e53e3e);
background: white;
box-shadow: none;
outline: none;
box-shadow: 0 0 0 3px var(--color-primary-bg, rgba(229, 62, 62, 0.08));
}
input:focus {
@@ -565,12 +582,12 @@ input:focus {
}
.input-wrapper.error {
border-color: #dc3545;
border-color: var(--color-danger, #dc3545);
background: #fff5f5;
}
.input-wrapper.success {
border-color: #4caf50;
border-color: var(--color-success, #4caf50);
background: #f8fff8;
}
@@ -597,9 +614,10 @@ input:focus {
outline: none;
font-size: 16px;
background: transparent;
color: #212529;
color: var(--color-text-primary, #212529);
box-shadow: none;
-webkit-appearance: none;
appearance: none;
}
.form-input:focus {
@@ -633,11 +651,11 @@ input:-webkit-autofill:active {
/* 内联发送验证码按钮样式 */
.send-code-btn-inline {
background: linear-gradient(135deg, #e53e3e, #ff6b6b);
background: linear-gradient(135deg, var(--color-primary, #e53e3e), var(--color-primary-light, #ff6b6b));
border: none;
border-radius: 12px;
border-radius: var(--radius-md, 12px);
font-weight: 500;
transition: all 0.3s ease;
transition: all var(--transition-base, 0.25s ease);
min-width: 120px;
flex-shrink: 0;
height: auto;
@@ -647,36 +665,37 @@ input:-webkit-autofill:active {
}
.send-code-btn-inline:hover:not(.is-disabled) {
background: linear-gradient(135deg, #d43030, #ff5a5a);
background: linear-gradient(135deg, var(--color-primary-dark, #d43030), #ff5a5a);
transform: translateY(-1px);
box-shadow: 0 4px 15px rgba(229, 62, 62, 0.3);
box-shadow: 0 4px 15px var(--color-primary-shadow, rgba(229, 62, 62, 0.3));
}
.send-code-btn-inline:active:not(.is-disabled) {
transform: translateY(0);
transform: translateY(0) scale(0.98);
}
.send-code-btn-inline.is-disabled {
background: #cccccc !important;
border-color: #cccccc !important;
color: #888 !important;
background: #d9d9d9 !important;
border-color: #d9d9d9 !important;
color: #999 !important;
transform: none !important;
box-shadow: none !important;
}
/* 提示文本 */
.error-text {
color: #ff4444;
color: var(--color-danger, #f56565);
font-size: 12px;
margin-top: 5px;
margin-left: 8px;
margin-top: 6px;
margin-left: 4px;
animation: slideUp 0.2s ease;
}
.tip-text {
color: #888888;
color: var(--color-text-tertiary, #a0aec0);
font-size: 12px;
margin-top: 5px;
margin-left: 8px;
margin-top: 6px;
margin-left: 4px;
}
/* 隐藏浏览器自带的密码控件 */
@@ -692,7 +711,7 @@ input::-webkit-credentials-auto-fill-button {
}
.form-input::placeholder {
color: #9ca3af;
color: var(--color-text-placeholder, #cbd5e0);
}
.password-toggle {
@@ -739,24 +758,25 @@ input::-webkit-credentials-auto-fill-button {
justify-content: center;
font-size: 10px;
color: transparent;
transition: all 0.3s;
transition: all 0.2s;
}
.checkbox-wrapper input:checked + .checkmark {
background: #e53e3e;
border-color: #e53e3e;
background: var(--color-primary, #e53e3e);
border-color: var(--color-primary, #e53e3e);
color: white;
}
/* 忘记密码链接 */
.forgot-password-link {
color: #e53e3e;
color: var(--color-primary, #e53e3e);
text-decoration: none;
font-size: 14px;
transition: all 0.3s;
transition: color var(--transition-fast, 0.15s ease);
}
.forgot-password-link:hover {
color: var(--color-primary-dark, #c53030);
text-decoration: underline;
}
@@ -768,22 +788,23 @@ input::-webkit-credentials-auto-fill-button {
font-size: 16px;
font-weight: 600;
height: 52px;
background: linear-gradient(135deg, #e53e3e, #ff6b6b);
background: linear-gradient(135deg, var(--color-primary, #e53e3e), var(--color-primary-light, #ff6b6b));
border: none;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(229, 62, 62, 0.25);
transition: all 0.3s ease;
border-radius: var(--radius-md, 12px);
box-shadow: 0 4px 20px var(--color-primary-shadow, rgba(229, 62, 62, 0.25));
transition: all var(--transition-base, 0.25s ease);
letter-spacing: 1px;
}
.login-btn:hover:not(:disabled) {
transform: translateY(-1px);
box-shadow: 0 6px 30px rgba(229, 62, 62, 0.35);
background: linear-gradient(135deg, #d43030, #ff5a5a);
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(229, 62, 62, 0.4);
background: linear-gradient(135deg, var(--color-primary-dark, #d43030), #ff5a5a);
border: none;
}
.login-btn:active:not(:disabled) {
transform: translateY(0);
transform: translateY(0) scale(0.98);
box-shadow: 0 2px 10px rgba(229, 62, 62, 0.3);
}
@@ -791,65 +812,71 @@ input::-webkit-credentials-auto-fill-button {
:deep(.el-input__wrapper) {
padding: 6px 16px;
box-shadow: none !important;
background-color: #f8f9fa;
border: 2px solid #e9ecef;
border-radius: 12px;
transition: all 0.3s ease;
background-color: var(--color-bg-input, #f7fafc);
border: 2px solid var(--color-border, #e2e8f0);
border-radius: var(--radius-md, 12px);
transition: all var(--transition-base, 0.25s ease);
}
:deep(.el-input__wrapper.is-focus) {
background-color: #fff;
border-color: #e53e3e;
box-shadow: 0 0 0 4px rgba(229, 62, 62, 0.1);
border-color: var(--color-primary, #e53e3e);
box-shadow: 0 0 0 3px var(--color-primary-bg, rgba(229, 62, 62, 0.08)) !important;
}
:deep(.el-input__prefix) {
margin-right: 12px;
color: #999;
color: var(--color-text-tertiary, #a0aec0);
transition: color var(--transition-base, 0.25s ease);
}
:deep(.el-input.is-focus .el-input__prefix) {
color: var(--color-primary, #e53e3e);
}
:deep(.el-input__inner) {
height: 44px;
font-size: 15px;
color: #333;
color: var(--color-text-primary, #1a202c);
}
:deep(.el-checkbox__label) {
font-size: 14px;
color: #666;
color: var(--color-text-secondary, #4a5568);
}
:deep(.el-checkbox__inner) {
border-color: #ddd;
transition: all 0.2s ease;
}
:deep(.el-checkbox__input.is-checked .el-checkbox__inner) {
background-color: #e53e3e;
border-color: #e53e3e;
background-color: var(--color-primary, #e53e3e);
border-color: var(--color-primary, #e53e3e);
}
:deep(.el-button.is-disabled) {
background: #cccccc;
border-color: #cccccc;
background: #d9d9d9;
border-color: #d9d9d9;
}
/* 注册链接 */
.register-link {
text-align: center;
font-size: 14px;
color: #666;
color: var(--color-text-secondary, #4a5568);
}
.register-link .link {
color: #e53e3e;
color: var(--color-primary, #e53e3e);
text-decoration: none;
margin-left: 5px;
font-weight: 500;
transition: color var(--transition-fast, 0.15s ease);
}
.register-link .link:hover {
color: var(--color-primary-dark, #c53030);
text-decoration: underline;
}
@@ -862,7 +889,6 @@ input::-webkit-credentials-auto-fill-button {
.login-form {
padding: 22px 20px 18px;
}
}
@media (max-width: 480px) {
@@ -919,6 +945,4 @@ input::-webkit-credentials-auto-fill-button {
gap: 8px;
}
}
/* 桌面端样式 - 这部分已在上面定义,这里移除重复定义 */
</style>

View File

@@ -163,7 +163,7 @@ export default {
<style scoped>
.lottery-info-page {
min-height: calc(100vh - 70px);
background: #f5f5f5;
background: var(--color-bg-page, #f0f2f5);
overflow-x: hidden;
padding-top: 16px; /* 顶部添加一些间距因为没有banner */
}

View File

@@ -181,9 +181,10 @@
<script>
import { lotteryApi } from '../api/index.js'
import { formatTime, formatFullTime } from '../utils/format.js'
export default {
name: 'LotterySelection',
name: 'LotteryPremium',
data() {
return {
showTip: false,
@@ -262,26 +263,8 @@ export default {
this.noticeTimer = null
}
},
// 格式化时间
formatTime(timestamp) {
const date = new Date(timestamp)
const year = String(date.getFullYear()).slice(-2)
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
},
// 格式化完整时间
formatFullTime(timestamp) {
const date = new Date(timestamp)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
},
formatTime,
formatFullTime,
// 显示公告列表
async showAnnouncementList() {
try {
@@ -308,7 +291,7 @@ export default {
<style scoped>
.home-page {
min-height: calc(100vh - 70px);
background: #f5f5f5;
background: var(--color-bg-page, #f0f2f5);
overflow-x: hidden;
}
@@ -524,11 +507,16 @@ export default {
}
.lottery-card.available:hover {
transform: translateY(-2px);
box-shadow: 0 4px 16px rgba(0,0,0,0.12);
transform: translateY(-3px);
box-shadow: 0 8px 24px rgba(0,0,0,0.15);
border-color: #ff6b35;
}
.lottery-card:active {
transform: scale(0.97);
transition-duration: 0.1s;
}
.lottery-card.disabled {
opacity: 0.85;
}

View File

@@ -181,6 +181,7 @@
<script>
import { lotteryApi } from '../api/index.js'
import { formatTime, formatFullTime } from '../utils/format.js'
export default {
name: 'LotterySelection',
@@ -264,26 +265,8 @@ export default {
this.noticeTimer = null
}
},
// 格式化时间
formatTime(timestamp) {
const date = new Date(timestamp)
const year = String(date.getFullYear()).slice(-2)
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
},
// 格式化完整时间
formatFullTime(timestamp) {
const date = new Date(timestamp)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
},
formatTime,
formatFullTime,
// 显示公告列表
async showAnnouncementList() {
try {
@@ -318,7 +301,7 @@ export default {
<style scoped>
.home-page {
min-height: calc(100vh - 70px);
background: #f5f5f5;
background: var(--color-bg-page, #f0f2f5);
overflow-x: hidden;
}
@@ -504,7 +487,7 @@ export default {
}
.premium-btn:active {
transform: translateY(0);
transform: translateY(0) scale(0.95);
}
.lottery-grid {
@@ -532,11 +515,16 @@ export default {
}
.lottery-card.available:hover {
transform: translateY(-2px);
box-shadow: 0 4px 16px rgba(0,0,0,0.12);
transform: translateY(-3px);
box-shadow: 0 8px 24px rgba(0,0,0,0.15);
border-color: #ff6b35;
}
.lottery-card:active {
transform: scale(0.97);
transition-duration: 0.1s;
}
.lottery-card.disabled {
opacity: 0.85;
}
@@ -709,6 +697,16 @@ export default {
border: 1px solid rgba(255, 255, 255, 0.3) !important;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes scaleIn {
from { opacity: 0; transform: scale(0.9); }
to { opacity: 1; transform: scale(1); }
}
.tip-overlay {
position: fixed;
top: 0;
@@ -721,16 +719,18 @@ export default {
justify-content: center;
z-index: 1000;
padding: 20px;
animation: fadeIn 0.2s ease;
}
.tip-content {
background: white;
border-radius: 16px;
border-radius: var(--radius-lg, 16px);
padding: 32px 24px;
text-align: center;
max-width: 300px;
width: 100%;
box-shadow: 0 16px 48px rgba(0,0,0,0.2);
box-shadow: var(--shadow-xl, 0 16px 48px rgba(0,0,0,0.2));
animation: scaleIn 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.tip-icon {
@@ -770,7 +770,7 @@ export default {
}
.tip-button:active {
transform: translateY(0);
transform: translateY(0) scale(0.96);
}
/* 响应式设计 */
@@ -1128,17 +1128,19 @@ export default {
justify-content: center;
z-index: 1000;
padding: 20px;
animation: fadeIn 0.2s ease;
}
.announcement-modal-content {
background: white;
border-radius: 16px;
border-radius: var(--radius-lg, 16px);
max-width: 600px;
width: 100%;
max-height: 80vh;
display: flex;
flex-direction: column;
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.2);
box-shadow: var(--shadow-xl, 0 16px 48px rgba(0, 0, 0, 0.2));
animation: scaleIn 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.announcement-modal-header {

View File

@@ -220,41 +220,8 @@
<script>
import { lotteryApi } from '../api/index.js'
import { userStore } from '../store/user.js'
import {
ElPageHeader,
ElCard,
ElButton,
ElIcon,
ElEmpty,
ElTag,
ElRadioGroup,
ElRadioButton,
ElPagination,
ElDescriptions,
ElDescriptionsItem,
ElSelect,
ElOption
} from 'element-plus'
import { Tickets } from '@element-plus/icons-vue'
export default {
name: 'PredictRecords',
components: {
ElPageHeader,
ElCard,
ElButton,
ElIcon,
ElEmpty,
ElTag,
ElRadioGroup,
ElRadioButton,
ElPagination,
ElDescriptions,
ElDescriptionsItem,
ElSelect,
ElOption,
Tickets
},
data() {
return {
loading: false,
@@ -825,6 +792,11 @@ export default {
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
}
.record-card-modern:active {
transform: scale(0.98);
transition-duration: 0.1s;
}
.record-header {
padding: 14px 16px 0 16px;
display: flex;

View File

@@ -458,37 +458,11 @@
import { userStore } from '../store/user'
import { lotteryApi } from '../api/index.js'
import QRCode from 'qrcode'
import { ElIcon, ElTable, ElTableColumn, ElMessage } from 'element-plus'
import CustomSelect from '../components/CustomSelect.vue'
import {
View,
TrendCharts,
Star,
Download,
Comment,
Reading,
Collection,
Tickets,
ShoppingBag,
Warning
} from '@element-plus/icons-vue'
export default {
name: 'Profile',
components: {
ElIcon,
View,
TrendCharts,
Star,
Download,
Comment,
Reading,
Collection,
ElTable,
ElTableColumn,
Tickets,
ShoppingBag,
Warning,
CustomSelect
},
data() {
@@ -596,7 +570,7 @@ export default {
const date = new Date(this.userStore.user.expireDate)
return date.toISOString().split('T')[0] // 只取日期部分 YYYY-MM-DD
}
return '2025-06-30'
return '暂无'
},
// 检查会员是否已过期
@@ -1055,8 +1029,8 @@ export default {
/* 用户中心容器 */
.profile-container {
min-height: calc(100vh - 85px);
background: #f5f5f5;
padding: 0 0 0px 0;
background: var(--color-bg-page, #f0f2f5);
padding: 0;
width: 100%;
}
@@ -1070,16 +1044,22 @@ export default {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
}
@keyframes cardEntry {
from { opacity: 0; transform: translateY(30px) scale(0.96); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
.login-card {
background: white;
border-radius: 20px;
border-radius: var(--radius-xl, 20px);
padding: 50px 30px;
text-align: center;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
box-shadow: var(--shadow-xl, 0 12px 40px rgba(0, 0, 0, 0.12));
max-width: 380px;
width: 100%;
position: relative;
overflow: hidden;
animation: cardEntry 0.5s ease;
}
.login-icon {
@@ -1338,13 +1318,19 @@ export default {
padding: 18px 10px;
cursor: pointer;
position: relative;
transition: background-color 0.3s ease;
transition: background-color 0.2s ease, transform 0.15s ease;
-webkit-tap-highlight-color: transparent;
}
.action-item:hover {
background-color: #f8f9fa;
}
.action-item:active {
transform: scale(0.95);
background-color: #f0f0f0;
}
.action-item:not(:last-child)::after {
content: '';
position: absolute;
@@ -1426,7 +1412,7 @@ export default {
}
.benefit-item:active {
transform: translateY(-1px);
transform: scale(0.95);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
@@ -1537,6 +1523,10 @@ export default {
background-color: #f8f9fa;
}
.function-list-item:active {
background-color: #f0f0f0;
}
.function-list-item:first-child {
border-radius: 15px 15px 0 0;
}
@@ -1719,9 +1709,10 @@ export default {
}
.modern-input:focus {
border-color: #ddd;
border-color: var(--color-primary, #e53e3e);
background: white;
outline: none;
box-shadow: 0 0 0 3px var(--color-primary-bg, rgba(229, 62, 62, 0.08));
}
.input-focus-border {
@@ -1826,7 +1817,7 @@ export default {
}
.primary-btn:active {
transform: translateY(0);
transform: translateY(0) scale(0.97);
}
/* 响应式设计 */

View File

@@ -150,22 +150,8 @@ import { userStore } from '../store/user'
import { lotteryApi } from '../api/index.js'
import { useToast } from 'vue-toastification'
import { useRouter } from 'vue-router'
import { ElCard, ElInput, ElButton, ElCheckbox } from 'element-plus'
import { User, Lock, Iphone, Key, Avatar } from '@element-plus/icons-vue'
export default {
name: 'Register',
components: {
ElCard,
ElInput,
ElButton,
ElCheckbox,
User,
Lock,
Iphone,
Key,
Avatar
},
setup() {
const toast = useToast()
const router = useRouter()
@@ -451,10 +437,7 @@ export default {
const formData = {
username: this.formData.username,
nickname: this.formData.nickname,
password: this.formData.password,
confirmPassword: this.formData.confirmPassword,
phone: this.formData.phone,
code: this.formData.code,
agreeTerms: this.formData.agreeTerms
};
sessionStorage.setItem('register_form_data', JSON.stringify(formData));
@@ -534,7 +517,7 @@ export default {
/* 注册页面容器 */
.register-page-container {
min-height: calc(100vh - 70px);
background: #f0f2f5;
background: var(--color-bg-page, #f0f2f5);
padding: 20px 20px 8px 20px;
}
@@ -609,28 +592,27 @@ export default {
position: relative;
display: flex;
align-items: center;
border: 2px solid #e9ecef;
border: 2px solid var(--color-border, #e9ecef);
border-radius: 6px;
background: #f8f9fa;
transition: all 0.3s ease;
background: var(--color-bg-input, #f8f9fa);
transition: all var(--transition-base, 0.25s ease);
min-height: 56px;
overflow: hidden;
}
.input-wrapper:focus-within {
border-color: #e9ecef;
border-color: var(--color-primary, #e53e3e);
background: white;
box-shadow: none;
outline: none;
box-shadow: 0 0 0 3px var(--color-primary-bg, rgba(229, 62, 62, 0.08));
}
.input-wrapper.error {
border-color: #dc3545;
border-color: var(--color-danger, #dc3545);
background: #fff5f5;
}
.input-wrapper.success {
border-color: #4caf50;
border-color: var(--color-success, #4caf50);
background: #f8fff8;
}
@@ -668,6 +650,7 @@ export default {
color: #212529;
box-shadow: none;
-webkit-appearance: none;
appearance: none;
}
.form-input:focus {
@@ -860,7 +843,7 @@ input::-webkit-credentials-auto-fill-button {
}
.register-btn:active:not(:disabled) {
transform: translateY(0);
transform: translateY(0) scale(0.98);
box-shadow: 0 2px 10px rgba(229, 62, 62, 0.3);
}

View File

@@ -112,18 +112,8 @@
import { lotteryApi } from '../api/index.js'
import { useToast } from 'vue-toastification'
import { useRouter } from 'vue-router'
import { ElInput, ElButton } from 'element-plus'
import { Lock, Iphone, Key } from '@element-plus/icons-vue'
export default {
name: 'ResetPassword',
components: {
ElInput,
ElButton,
Lock,
Iphone,
Key
},
setup() {
const toast = useToast()
const router = useRouter()
@@ -353,7 +343,7 @@ export default {
/* 页面容器 */
.reset-password-page-container {
min-height: calc(100vh - 70px);
background: #f0f2f5;
background: var(--color-bg-page, #f0f2f5);
padding: 20px 20px 8px 20px;
}

View File

@@ -91,14 +91,8 @@
</template>
<script>
import { ElPageHeader, ElCard } from 'element-plus'
export default {
name: 'UserAgreement',
components: {
ElPageHeader,
ElCard
},
methods: {
goBack() {
this.$router.go(-1)

View File

@@ -120,18 +120,11 @@
import { ref, reactive, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { User, Lock, Key, Document } from '@element-plus/icons-vue'
import { lotteryApi } from '../../api/index.js'
import { userStore } from '../../store/user.js'
export default {
name: 'AdminLogin',
components: {
User,
Lock,
Key,
Document
},
setup() {
const router = useRouter()
const loginFormRef = ref()

View File

@@ -270,32 +270,10 @@
<script>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
Bell,
CircleCheck,
Edit,
Close,
Search,
Refresh,
Plus,
View,
Delete
} from '@element-plus/icons-vue'
import { lotteryApi } from '../../api/index.js'
export default {
name: 'AnnouncementManagement',
components: {
Bell,
CircleCheck,
Edit,
Close,
Search,
Refresh,
Plus,
View,
Delete
},
setup() {
const loading = ref(false)
const submitting = ref(false)

View File

@@ -224,21 +224,6 @@
<script>
import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue'
import {
User,
Key,
Ticket,
TrendCharts,
Operation,
Document,
Setting,
InfoFilled,
Clock,
ArrowRight,
View,
Sunny,
DataLine
} from '@element-plus/icons-vue'
import { userStore } from '../../store/user.js'
import { lotteryApi } from '../../api/index.js'
import { useRouter } from 'vue-router'
@@ -246,21 +231,6 @@ import * as echarts from 'echarts'
export default {
name: 'AdminDashboard',
components: {
User,
Key,
Ticket,
TrendCharts,
Operation,
Document,
Setting,
InfoFilled,
Clock,
ArrowRight,
View,
Sunny,
DataLine
},
setup() {
const router = useRouter()

View File

@@ -218,35 +218,8 @@
import { lotteryApi } from '../../api/index.js'
import dltLotteryApi from '../../api/dlt/index.js'
import { userStore } from '../../store/user.js'
import {
ElCard,
ElRow,
ElCol,
ElButton,
ElIcon
} from 'element-plus'
import {
Document,
Warning,
Plus,
InfoFilled,
FolderOpened
} from '@element-plus/icons-vue'
export default {
name: 'AdminDltExcelImportManagement',
components: {
ElCard,
ElRow,
ElCol,
ElButton,
ElIcon,
Document,
Warning,
Plus,
InfoFilled,
FolderOpened
},
data() {
return {
// 权限验证
@@ -461,7 +434,7 @@ export default {
<style scoped>
.excel-import-management {
min-height: 100vh;
background: #f5f5f5;
background: var(--color-bg-page, #f0f2f5);
padding: 24px;
}

View File

@@ -217,35 +217,8 @@
<script>
import { lotteryApi } from '../../api/index.js'
import { userStore } from '../../store/user.js'
import {
ElCard,
ElRow,
ElCol,
ElButton,
ElIcon
} from 'element-plus'
import {
Document,
Warning,
Plus,
InfoFilled,
FolderOpened
} from '@element-plus/icons-vue'
export default {
name: 'AdminExcelImportManagement',
components: {
ElCard,
ElRow,
ElCol,
ElButton,
ElIcon,
Document,
Warning,
Plus,
InfoFilled,
FolderOpened
},
data() {
return {
// 权限验证
@@ -472,7 +445,7 @@ export default {
<style scoped>
.excel-import-management {
min-height: 100vh;
background: #f5f5f5;
background: var(--color-bg-page, #f0f2f5);
padding: 24px;
}

View File

@@ -141,23 +141,11 @@
<script>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import {
Clock,
Refresh,
Search,
Filter
} from '@element-plus/icons-vue'
import { lotteryApi } from '../../api/index.js'
import { userStore } from '../../store/user.js'
export default {
name: 'OperationHistory',
components: {
Clock,
Refresh,
Search,
Filter
},
setup() {
// 筛选表单
const filterForm = reactive({

View File

@@ -423,28 +423,12 @@
<script>
import { ref, reactive, computed, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
Search,
Refresh,
Plus,
Download,
Edit,
Delete
} from '@element-plus/icons-vue'
import { lotteryApi } from '../../api/index.js'
import { userStore } from '../../store/user.js'
import { useRouter } from 'vue-router'
export default {
name: 'UserList',
components: {
Search,
Refresh,
Plus,
Download,
Edit,
Delete
},
setup() {
const router = useRouter()
// 权限检查

View File

@@ -374,33 +374,11 @@
<script>
import { ref, reactive, computed, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
Key,
Check,
User,
Plus,
Search,
List,
Refresh,
Download,
CopyDocument
} from '@element-plus/icons-vue'
import { lotteryApi } from '../../api/index.js'
import { userStore } from '../../store/user.js'
export default {
name: 'VipCodeManagement',
components: {
Key,
Check,
User,
Plus,
Search,
List,
Refresh,
Download,
CopyDocument
},
setup() {
// 统计数据
const stats = reactive({

View File

@@ -157,47 +157,17 @@
import { ref, computed, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
DataBoard,
User,
Key,
Document,
Fold,
Expand,
ArrowDown,
Refresh,
Setting,
SwitchButton,
Clock,
Bell,
Aim,
Trophy
} from '@element-plus/icons-vue'
import { userStore } from '../../../store/user.js'
import { lotteryApi } from '../../../api/index.js'
export default {
name: 'AdminLayout',
components: {
DataBoard,
User,
Key,
Document,
Fold,
Expand,
ArrowDown,
Bell,
Refresh,
Setting,
SwitchButton,
Clock
},
setup() {
const route = useRoute()
const router = useRouter()
const isCollapse = ref(false)
const userName = ref('管理员')
const userAvatar = ref('https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png')
const userAvatar = ref('/assets/home/default-avatar.svg')
const userRole = ref('')
// 当前激活的菜单项

View File

@@ -93,28 +93,8 @@
<script>
import { dltLotteryApi } from '../../api/dlt/index.js'
import {
ElButton,
ElCard,
ElSkeleton,
ElAlert,
ElTable,
ElTableColumn,
ElEmpty
} from 'element-plus'
import { ArrowLeft } from '@element-plus/icons-vue'
export default {
name: 'DltTableAnalysis',
components: {
ElButton,
ElCard,
ElSkeleton,
ElAlert,
ElTable,
ElTableColumn,
ElEmpty
},
data() {
return {
drawsData: [],

View File

@@ -136,14 +136,10 @@
<script>
import dltLotteryApi from '../../api/dlt/index.js'
import { userStore } from '../../store/user.js'
import { ElSelect, ElOption, ElMessage } from 'element-plus'
import { ElMessage } from 'element-plus'
export default {
name: 'DltHitAnalysis',
components: {
ElSelect,
ElOption
},
data() {
return {
loading: false,

View File

@@ -1176,44 +1176,12 @@ import { lotteryApi } from '../../api'
import { dltLotteryApi } from '../../api/dlt'
import { userStore } from '../../store/user'
import AlgorithmProcessModal from '../../components/AlgorithmProcessModal.vue'
import {
ElButton,
ElCard,
ElSteps,
ElStep,
ElInput,
ElDialog,
ElAlert,
ElSelect,
ElOption,
ElCheckbox,
ElDivider,
ElSkeleton,
ElTag,
ElMessage
} from 'element-plus'
import { ArrowLeft, InfoFilled, Trophy } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
export default {
name: 'DltHome',
components: {
AlgorithmProcessModal,
ElButton,
ElCard,
ElSteps,
ElStep,
ElInput,
ElDialog,
ElAlert,
ElSelect,
ElOption,
ElCheckbox,
ElDivider,
ElSkeleton,
ElTag,
ArrowLeft,
InfoFilled,
Trophy
AlgorithmProcessModal
},
data() {
return {
@@ -2233,7 +2201,7 @@ export default {
/* 基础样式参考双色球界面但使用绿色主题 */
.home-container {
padding: 20px 20px 8px 20px;
background-color: #f0f2f5;
background-color: var(--color-bg-page, #f0f2f5);
min-height: calc(100vh - 70px);
display: flex;
flex-direction: column;
@@ -2561,12 +2529,18 @@ export default {
}
.position-item:hover {
transform: translateY(-1px);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.position-item:active {
transform: scale(0.97);
transition-duration: 0.1s;
}
.position-item.selected {
border-color: #4CAF50;
background: rgba(76, 175, 80, 0.1);
background: rgba(76, 175, 80, 0.08);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(76, 175, 80, 0.2);
}

View File

@@ -273,33 +273,8 @@
<script>
import { dltLotteryApi } from '@/api/dlt'
import {
ElButton,
ElCard,
ElAvatar,
ElDivider,
ElAlert,
ElResult,
ElIcon,
ElCollapse,
ElCollapseItem
} from 'element-plus'
import { ArrowLeft, InfoFilled } from '@element-plus/icons-vue'
export default {
name: 'DltLineAnalysis',
components: {
ElButton,
ElCard,
ElAvatar,
ElDivider,
ElAlert,
ElResult,
ElIcon,
ElCollapse,
ElCollapseItem,
InfoFilled
},
data() {
return {
analysisType: '', // 'front-front', 'back-back', 'front-back', 'back-front'

View File

@@ -586,7 +586,7 @@ export default {
<style scoped>
.dlt-lottery-page {
min-height: calc(100vh - 70px);
background: #f5f5f5;
background: var(--color-bg-page, #f0f2f5);
padding: 16px 0;
}

View File

@@ -218,41 +218,8 @@
<script>
import { dltLotteryApi } from '../../api/dlt/index.js'
import { userStore } from '../../store/user.js'
import {
ElPageHeader,
ElCard,
ElButton,
ElIcon,
ElEmpty,
ElTag,
ElRadioGroup,
ElRadioButton,
ElPagination,
ElDescriptions,
ElDescriptionsItem,
ElSelect,
ElOption
} from 'element-plus'
import { Tickets } from '@element-plus/icons-vue'
export default {
name: 'DltPredictRecords',
components: {
ElPageHeader,
ElCard,
ElButton,
ElIcon,
ElEmpty,
ElTag,
ElRadioGroup,
ElRadioButton,
ElPagination,
ElDescriptions,
ElDescriptionsItem,
ElSelect,
ElOption,
Tickets
},
data() {
return {
loading: false,

View File

@@ -80,14 +80,10 @@
<script>
import dltLotteryApi from '../../api/dlt/index.js'
import { userStore } from '../../store/user.js'
import { ElSelect, ElOption, ElMessage } from 'element-plus'
import { ElMessage } from 'element-plus'
export default {
name: 'DltPrizeStatistics',
components: {
ElSelect,
ElOption
},
data() {
return {
loading: false,

View File

@@ -272,43 +272,8 @@
<script>
import { dltLotteryApi } from '@/api/dlt'
import {
ElButton,
ElCard,
ElAvatar,
ElDivider,
ElAlert,
ElResult,
ElTag,
ElStatistic,
ElTooltip,
ElIcon,
ElCollapse,
ElCollapseItem,
ElTable,
ElTableColumn
} from 'element-plus'
import { ArrowLeft, InfoFilled } from '@element-plus/icons-vue'
export default {
name: 'DltSurfaceAnalysis',
components: {
ElButton,
ElCard,
ElAvatar,
ElDivider,
ElAlert,
ElResult,
ElTag,
ElStatistic,
ElTooltip,
ElIcon,
ElCollapse,
ElCollapseItem,
ElTable,
ElTableColumn,
InfoFilled
},
data() {
return {
analysisType: '', // 'front-front', 'front-back', 'back-back', 'back-front'

View File

@@ -149,46 +149,8 @@
<script>
import { dltLotteryApi } from '@/api/dlt'
import {
ElButton,
ElCard,
ElRadioGroup,
ElRadioButton,
ElSkeleton,
ElAlert,
ElTable,
ElTableColumn,
ElPagination,
ElEmpty,
ElIcon
} from 'element-plus'
import {
ArrowLeft,
Document,
Sort,
Histogram,
Menu
} from '@element-plus/icons-vue'
export default {
name: 'DltTrendAnalysis',
components: {
ElButton,
ElCard,
ElRadioGroup,
ElRadioButton,
ElSkeleton,
ElAlert,
ElTable,
ElTableColumn,
ElPagination,
ElEmpty,
ElIcon,
Document,
Sort,
Histogram,
Menu
},
data() {
return {
loading: false,

View File

@@ -102,14 +102,10 @@
<script>
import dltLotteryApi from '../../api/dlt/index.js'
import { userStore } from '../../store/user.js'
import { ElSelect, ElOption, ElMessage } from 'element-plus'
import { ElMessage } from 'element-plus'
export default {
name: 'DltUsageStats',
components: {
ElSelect,
ElOption
},
data() {
return {
loading: false,

View File

@@ -976,44 +976,12 @@
import { dltLotteryApi } from '../../api/dlt'
import { userStore } from '../../store/user'
import AlgorithmProcessModal from '../../components/AlgorithmProcessModal.vue'
import {
ElButton,
ElCard,
ElSteps,
ElStep,
ElInput,
ElDialog,
ElAlert,
ElSelect,
ElOption,
ElCheckbox,
ElDivider,
ElSkeleton,
ElTag,
ElMessage
} from 'element-plus'
import { ArrowLeft, InfoFilled, Trophy } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
export default {
name: 'DltHome',
components: {
AlgorithmProcessModal,
ElButton,
ElCard,
ElSteps,
ElStep,
ElInput,
ElDialog,
ElAlert,
ElSelect,
ElOption,
ElCheckbox,
ElDivider,
ElSkeleton,
ElTag,
ArrowLeft,
InfoFilled,
Trophy
AlgorithmProcessModal
},
data() {
return {

View File

@@ -836,56 +836,10 @@
import { lotteryApi } from '../../api'
import { userStore } from '../../store/user'
import AlgorithmProcessModal from '../../components/AlgorithmProcessModal.vue'
import {
ElButton,
ElCard,
ElSteps,
ElStep,
ElInput,
ElRadioGroup,
ElRadioButton,
ElDialog,
ElAlert,
ElCheckbox,
ElDivider,
ElSkeleton,
ElTag,
ElSelect,
ElOption,
ElTable,
ElTableColumn
} from 'element-plus'
import { ArrowLeft, Warning, Check, InfoFilled, Trophy, QuestionFilled, Bell, Promotion } from '@element-plus/icons-vue'
export default {
name: 'Home',
components: {
AlgorithmProcessModal,
ElButton,
ElCard,
ElSteps,
ElStep,
ElInput,
ElRadioGroup,
ElRadioButton,
ElDialog,
ElAlert,
ElCheckbox,
ElDivider,
ElSkeleton,
ElTag,
ArrowLeft,
Warning,
Check,
InfoFilled,
QuestionFilled,
Bell,
Promotion,
ElSelect,
ElOption,
ElTable,
ElTableColumn,
Trophy
AlgorithmProcessModal
},
data() {
return {

View File

@@ -123,14 +123,10 @@
<script>
import api, { lotteryApi } from '../../api/index.js'
import { userStore } from '../../store/user.js'
import { ElSelect, ElOption, ElMessage } from 'element-plus'
import { ElMessage } from 'element-plus'
export default {
name: 'HitAnalysis',
components: {
ElSelect,
ElOption
},
data() {
return {
loading: false,

View File

@@ -1106,52 +1106,10 @@
import { lotteryApi } from '../../api'
import { userStore } from '../../store/user'
import AlgorithmProcessModal from '../../components/AlgorithmProcessModal.vue'
import {
ElButton,
ElCard,
ElSteps,
ElStep,
ElInput,
ElRadioGroup,
ElRadioButton,
ElDialog,
ElAlert,
ElCheckbox,
ElDivider,
ElSkeleton,
ElTag,
ElSelect,
ElOption
} from 'element-plus'
import { ArrowLeft, Warning, Check, InfoFilled, Trophy, QuestionFilled, Bell, Promotion } from '@element-plus/icons-vue'
export default {
name: 'Home',
components: {
AlgorithmProcessModal,
ElButton,
ElCard,
ElSteps,
ElStep,
ElInput,
ElRadioGroup,
ElRadioButton,
ElDialog,
ElAlert,
ElCheckbox,
ElDivider,
ElSkeleton,
ElTag,
ArrowLeft,
Warning,
Check,
InfoFilled,
QuestionFilled,
Bell,
Promotion,
ElSelect,
ElOption,
Trophy
AlgorithmProcessModal
},
data() {
return {
@@ -2186,6 +2144,14 @@ export default {
box-shadow: 0 6px 16px rgba(229, 62, 62, 0.4);
}
.custom-btn-primary:active {
transform: translateY(0) scale(0.97);
}
.custom-btn-default:active {
transform: scale(0.97);
}
/* 消息弹窗特殊样式 */
.custom-message-dialog {
width: 400px;
@@ -2282,7 +2248,7 @@ export default {
/* 页面容器 */
.home-container {
padding: 20px 20px 8px 20px;
background-color: #f0f2f5;
background-color: var(--color-bg-page, #f0f2f5);
min-height: calc(100vh - 70px);
display: flex;
flex-direction: column;
@@ -2457,14 +2423,20 @@ export default {
}
.position-item:hover {
transform: translateY(-1px);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.position-item:active {
transform: scale(0.97);
transition-duration: 0.1s;
}
.position-item.selected {
border-color: #e53e3e;
background: rgba(229, 62, 62, 0.1);
border-color: var(--color-primary, #e53e3e);
background: var(--color-primary-bg, rgba(229, 62, 62, 0.08));
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(229, 62, 62, 0.2);
box-shadow: 0 4px 12px var(--color-primary-shadow, rgba(229, 62, 62, 0.2));
}
.position-title {
@@ -3138,7 +3110,7 @@ export default {
}
.login-confirm-btn:active {
transform: translateY(0);
transform: translateY(0) scale(0.96);
}
.single-btn {

View File

@@ -263,33 +263,8 @@
<script>
import { lotteryApi } from '@/api'
import {
ElButton,
ElCard,
ElAvatar,
ElDivider,
ElAlert,
ElResult,
ElIcon,
ElCollapse,
ElCollapseItem
} from 'element-plus'
import { ArrowLeft, InfoFilled } from '@element-plus/icons-vue'
export default {
name: 'LineAnalysis',
components: {
ElButton,
ElCard,
ElAvatar,
ElDivider,
ElAlert,
ElResult,
ElIcon,
ElCollapse,
ElCollapseItem,
InfoFilled
},
data() {
return {
analysisType: '', // 'red-red', 'blue-blue', 'red-blue', 'blue-red'

View File

@@ -577,7 +577,7 @@ export default {
<style scoped>
.ssq-lottery-page {
min-height: calc(100vh - 70px);
background: #f5f5f5;
background: var(--color-bg-page, #f0f2f5);
padding: 16px 0;
}

View File

@@ -80,14 +80,8 @@
<script>
import api from '../../api/index.js'
import { userStore } from '../../store/user.js'
import { ElSelect, ElOption } from 'element-plus'
export default {
name: 'PrizeStatistics',
components: {
ElSelect,
ElOption
},
data() {
return {
loading: false,

View File

@@ -93,28 +93,8 @@
<script>
import { lotteryApi } from '../../api/index.js'
import {
ElButton,
ElCard,
ElSkeleton,
ElAlert,
ElTable,
ElTableColumn,
ElEmpty
} from 'element-plus'
import { ArrowLeft } from '@element-plus/icons-vue'
export default {
name: 'SsqTableAnalysis',
components: {
ElButton,
ElCard,
ElSkeleton,
ElAlert,
ElTable,
ElTableColumn,
ElEmpty
},
data() {
return {
drawsData: [],

View File

@@ -251,43 +251,8 @@
<script>
import { lotteryApi } from '@/api'
import {
ElButton,
ElCard,
ElAvatar,
ElDivider,
ElAlert,
ElResult,
ElTag,
ElStatistic,
ElTooltip,
ElIcon,
ElCollapse,
ElCollapseItem,
ElTable,
ElTableColumn
} from 'element-plus'
import { ArrowLeft, InfoFilled } from '@element-plus/icons-vue'
export default {
name: 'SurfaceAnalysis',
components: {
ElButton,
ElCard,
ElAvatar,
ElDivider,
ElAlert,
ElResult,
ElTag,
ElStatistic,
ElTooltip,
ElIcon,
ElCollapse,
ElCollapseItem,
ElTable,
ElTableColumn,
InfoFilled
},
data() {
return {
analysisType: '', // 'red-red', 'red-blue', 'blue-red'

View File

@@ -149,46 +149,8 @@
<script>
import { lotteryApi } from '@/api'
import {
ElButton,
ElCard,
ElRadioGroup,
ElRadioButton,
ElSkeleton,
ElAlert,
ElTable,
ElTableColumn,
ElPagination,
ElEmpty,
ElIcon
} from 'element-plus'
import {
ArrowLeft,
Document,
Sort,
Histogram,
Menu
} from '@element-plus/icons-vue'
export default {
name: 'TrendAnalysis',
components: {
ElButton,
ElCard,
ElRadioGroup,
ElRadioButton,
ElSkeleton,
ElAlert,
ElTable,
ElTableColumn,
ElPagination,
ElEmpty,
ElIcon,
Document,
Sort,
Histogram,
Menu
},
data() {
return {
loading: false,

View File

@@ -102,14 +102,8 @@
<script>
import api from '../../api/index.js'
import { userStore } from '../../store/user.js'
import { ElSelect, ElOption } from 'element-plus'
export default {
name: 'UsageStats',
components: {
ElSelect,
ElOption
},
data() {
return {
loading: false,