功能测试正常切可用的第一版 #1
4 changed files with 657 additions and 659 deletions
394
src/assets/network-bettle.css
Normal file
394
src/assets/network-bettle.css
Normal file
|
|
@ -0,0 +1,394 @@
|
||||||
|
.network-battle-page {
|
||||||
|
background: linear-gradient(135deg, #f7f9fc, #e2e7ed);
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 2rem auto;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||||
|
text-align: center;
|
||||||
|
padding: 2rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.network-battle-page h1 {
|
||||||
|
font-size: 2.2rem;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connection-section {
|
||||||
|
background-color: rgba(255, 255, 255, 0.7);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 1.5rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.connection-type {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connection-type button {
|
||||||
|
background: rgba(255, 255, 255, 0.8);
|
||||||
|
color: #555;
|
||||||
|
border: 2px solid #ddd;
|
||||||
|
border-radius: 30px;
|
||||||
|
padding: 0.7rem 1.5rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connection-type button.active {
|
||||||
|
background: linear-gradient(90deg, #84b9ff, #32a8ff, #0faeff);
|
||||||
|
color: white;
|
||||||
|
border-color: transparent;
|
||||||
|
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.host-section, .join-section {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.local-info {
|
||||||
|
background-color: rgba(255, 255, 255, 0.9);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.peer-id {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #0077cc;
|
||||||
|
background: rgba(0, 119, 204, 0.1);
|
||||||
|
padding: 0.3rem 0.6rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin: 0 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-button {
|
||||||
|
background: rgba(0, 119, 204, 0.1);
|
||||||
|
color: #0077cc;
|
||||||
|
border: 1px solid #0077cc;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 0.3rem 0.8rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-button:hover {
|
||||||
|
background: rgba(0, 119, 204, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input {
|
||||||
|
padding: 0.8rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 2px solid #ddd;
|
||||||
|
width: 80%;
|
||||||
|
max-width: 400px;
|
||||||
|
text-align: center;
|
||||||
|
outline: none;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group input:focus {
|
||||||
|
border-color: #007ACC;
|
||||||
|
box-shadow: 0 0 0 2px rgba(0,122,204,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-settings {
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin-left: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
padding: 0.6rem 1rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 2px solid #ddd;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
color: #555;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
select:focus {
|
||||||
|
border-color: #007ACC;
|
||||||
|
box-shadow: 0 0 0 2px rgba(0,122,204,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: linear-gradient(90deg, #84b9ff, #32a8ff, #0faeff);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 30px;
|
||||||
|
padding: 0.7rem 1.5rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||||||
|
margin: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 6px 8px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled {
|
||||||
|
background: #cccccc;
|
||||||
|
cursor: not-allowed;
|
||||||
|
transform: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.players-info {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player {
|
||||||
|
background-color: rgba(255, 255, 255, 0.7);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 1rem;
|
||||||
|
width: 45%;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-turn {
|
||||||
|
border-color: #32a8ff;
|
||||||
|
background-color: rgba(50, 168, 255, 0.1);
|
||||||
|
box-shadow: 0 0 8px rgba(50, 168, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.player h3 {
|
||||||
|
margin: 0 0 0.5rem 0;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
color: #42b883;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-section p {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-section input {
|
||||||
|
margin: 1rem 0;
|
||||||
|
padding: 0.8rem;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 2px solid #ddd;
|
||||||
|
width: 200px;
|
||||||
|
text-align: center;
|
||||||
|
outline: none;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-section input:focus {
|
||||||
|
border-color: #007ACC;
|
||||||
|
box-shadow: 0 0 0 2px rgba(0,122,204,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-section input:disabled {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timer-section p {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #e74c3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback-container {
|
||||||
|
height: 30px;
|
||||||
|
margin: 10px 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback {
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: bold;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback.correct {
|
||||||
|
background-color: rgba(66, 184, 131, 0.2);
|
||||||
|
color: #2a8c5f;
|
||||||
|
border: 1px solid #42b883;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback.wrong {
|
||||||
|
background-color: rgba(231, 76, 60, 0.2);
|
||||||
|
color: #c0392b;
|
||||||
|
border: 1px solid #e74c3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.correct-answer {
|
||||||
|
animation: pulse-green 0.5s;
|
||||||
|
border-color: #42b883 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrong-answer {
|
||||||
|
animation: pulse-red 0.5s;
|
||||||
|
border-color: #e74c3c !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-messages {
|
||||||
|
height: 40px;
|
||||||
|
margin: 1rem 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-message {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
animation: fade-in 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-message.success {
|
||||||
|
background-color: rgba(66, 184, 131, 0.2);
|
||||||
|
color: #2a8c5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-message.error {
|
||||||
|
background-color: rgba(231, 76, 60, 0.2);
|
||||||
|
color: #c0392b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-message.info {
|
||||||
|
background-color: rgba(52, 152, 219, 0.2);
|
||||||
|
color: #2980b9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-result-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 10;
|
||||||
|
animation: fade-in 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-result {
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 2rem;
|
||||||
|
width: 90%;
|
||||||
|
max-width: 500px;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-result h2 {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.final-scores {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.final-scores p {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-message {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-message.win {
|
||||||
|
color: #42b883;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-message.lose {
|
||||||
|
color: #e74c3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-message.draw {
|
||||||
|
color: #f39c12;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 动画效果 */
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.5s, transform 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-from,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px) translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse-green {
|
||||||
|
0% { box-shadow: 0 0 0 0 rgba(66, 184, 131, 0.7); }
|
||||||
|
70% { box-shadow: 0 0 0 10px rgba(66, 184, 131, 0); }
|
||||||
|
100% { box-shadow: 0 0 0 0 rgba(66, 184, 131, 0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse-red {
|
||||||
|
0% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0.7); }
|
||||||
|
70% { box-shadow: 0 0 0 10px rgba(231, 76, 60, 0); }
|
||||||
|
100% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
from { opacity: 0; }
|
||||||
|
to { opacity: 1; }
|
||||||
|
}
|
||||||
220
src/assets/practice.css
Normal file
220
src/assets/practice.css
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
.practice-page {
|
||||||
|
background: linear-gradient(135deg, #f7f9fc, #e2e7ed);
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 2rem auto;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||||
|
text-align: center;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.practice-page h1 {
|
||||||
|
font-size: 2.2rem;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
header label {
|
||||||
|
margin-left: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
header select {
|
||||||
|
padding: 0.6rem 1rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 2px solid #ddd;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
color: #555;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
header select:focus {
|
||||||
|
border-color: #007ACC;
|
||||||
|
box-shadow: 0 0 0 2px rgba(0,122,204,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: linear-gradient(90deg, #84b9ff, #32a8ff, #0faeff);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 30px;
|
||||||
|
padding: 0.7rem 1.5rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||||||
|
margin: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 6px 8px rgba(0,0,0,0.15);
|
||||||
|
background: linear-gradient(90deg, #84b9ff, #32a8ff, #0faeff);
|
||||||
|
}
|
||||||
|
|
||||||
|
header button {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
padding: 0.7rem 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-section p {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-section input {
|
||||||
|
margin: 1rem 0;
|
||||||
|
padding: 0.8rem;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 2px solid #ddd;
|
||||||
|
width: 200px;
|
||||||
|
text-align: center;
|
||||||
|
outline: none;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-section input:focus {
|
||||||
|
border-color: #007ACC;
|
||||||
|
box-shadow: 0 0 0 2px rgba(0,122,204,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.timer-section p {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #e74c3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-section p {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #42b883;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
margin-top: 2rem;
|
||||||
|
padding-top: 1.5rem;
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer p {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #555;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer ul {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 1rem 0;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: auto;
|
||||||
|
/* 移除背景色和内边距,使其更扁平 */
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer li {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.8rem 1rem;
|
||||||
|
background-color: rgba(255, 255, 255, 0.7);
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
border-left: 3px solid #32a8ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer li:hover {
|
||||||
|
background-color: white;
|
||||||
|
transform: translateX(2px);
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
footer button {
|
||||||
|
background: linear-gradient(90deg, #ff7675, #d63031);
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
padding: 0.6rem 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer button:hover {
|
||||||
|
background: linear-gradient(90deg, #ff6b6b, #c0392b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 答题反馈动画 */
|
||||||
|
.feedback-container {
|
||||||
|
height: 30px;
|
||||||
|
margin: 10px 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback {
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: bold;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback.correct {
|
||||||
|
background-color: rgba(66, 184, 131, 0.2);
|
||||||
|
color: #2a8c5f;
|
||||||
|
border: 1px solid #42b883;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback.wrong {
|
||||||
|
background-color: rgba(231, 76, 60, 0.2);
|
||||||
|
color: #c0392b;
|
||||||
|
border: 1px solid #e74c3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 输入框的反馈效果 */
|
||||||
|
.correct-answer {
|
||||||
|
animation: pulse-green 0.5s;
|
||||||
|
border-color: #42b883 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrong-answer {
|
||||||
|
animation: pulse-red 0.5s;
|
||||||
|
border-color: #e74c3c !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 淡入淡出动画 */
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.5s, transform 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-from,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px) translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 脉动动画效果 */
|
||||||
|
@keyframes pulse-green {
|
||||||
|
0% { box-shadow: 0 0 0 0 rgba(66, 184, 131, 0.7); }
|
||||||
|
70% { box-shadow: 0 0 0 10px rgba(66, 184, 131, 0); }
|
||||||
|
100% { box-shadow: 0 0 0 0 rgba(66, 184, 131, 0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse-red {
|
||||||
|
0% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0.7); }
|
||||||
|
70% { box-shadow: 0 0 0 10px rgba(231, 76, 60, 0); }
|
||||||
|
100% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0); }
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
<button @click="mode = 'host'" :class="{ active: mode === 'host' }">创建房间</button>
|
<button @click="mode = 'host'" :class="{ active: mode === 'host' }">创建房间</button>
|
||||||
<button @click="mode = 'join'" :class="{ active: mode === 'join' }">加入房间</button>
|
<button @click="mode = 'join'" :class="{ active: mode === 'join' }">加入房间</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="mode === 'host'" class="host-section">
|
<div v-if="mode === 'host'" class="host-section">
|
||||||
<div v-if="localPeerId" class="local-info">
|
<div v-if="localPeerId" class="local-info">
|
||||||
<p>你的房间ID: <span class="peer-id">{{ localPeerId }}</span></p>
|
<p>你的房间ID: <span class="peer-id">{{ localPeerId }}</span></p>
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
</div>
|
</div>
|
||||||
<p v-if="connectionStatus">{{ connectionStatus }}</p>
|
<p v-if="connectionStatus">{{ connectionStatus }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="mode === 'join'" class="join-section">
|
<div v-if="mode === 'join'" class="join-section">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<label for="remotePeerId">输入房间ID:</label>
|
<label for="remotePeerId">输入房间ID:</label>
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
<p v-if="connectionStatus">{{ connectionStatus }}</p>
|
<p v-if="connectionStatus">{{ connectionStatus }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="isConnected && !isGameActive" class="game-settings">
|
<div v-if="isConnected && !isGameActive" class="game-settings">
|
||||||
<label for="difficulty">选择难度:</label>
|
<label for="difficulty">选择难度:</label>
|
||||||
<select id="difficulty" v-model="selectedDifficulty">
|
<select id="difficulty" v-model="selectedDifficulty">
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
<button @click="startGame">开始游戏</button>
|
<button @click="startGame">开始游戏</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main v-if="isGameActive">
|
<main v-if="isGameActive">
|
||||||
<div class="players-info">
|
<div class="players-info">
|
||||||
<div class="player local" :class="{ 'player-turn': localPlayerTurn }">
|
<div class="player local" :class="{ 'player-turn': localPlayerTurn }">
|
||||||
|
|
@ -49,7 +49,7 @@
|
||||||
<p class="score">得分: {{ remoteScore }}</p>
|
<p class="score">得分: {{ remoteScore }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section class="question-section">
|
<section class="question-section">
|
||||||
<p>{{ currentQuestion.question }}</p>
|
<p>{{ currentQuestion.question }}</p>
|
||||||
<input type="text" v-model="userAnswer" @keyup.enter="submitAnswer"
|
<input type="text" v-model="userAnswer" @keyup.enter="submitAnswer"
|
||||||
|
|
@ -58,7 +58,7 @@
|
||||||
:disabled="!isGameActive || !localPlayerTurn" />
|
:disabled="!isGameActive || !localPlayerTurn" />
|
||||||
<button @click="submitAnswer" :disabled="!isGameActive || !localPlayerTurn">提交答案</button>
|
<button @click="submitAnswer" :disabled="!isGameActive || !localPlayerTurn">提交答案</button>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class="feedback-container">
|
<div class="feedback-container">
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<div v-if="answerFeedback === 'correct'" class="feedback correct">
|
<div v-if="answerFeedback === 'correct'" class="feedback correct">
|
||||||
|
|
@ -71,18 +71,18 @@
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section class="timer-section">
|
<section class="timer-section">
|
||||||
<p>剩余时间: {{ timeLeft }} 秒</p>
|
<p>剩余时间: {{ timeLeft }} 秒</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class="game-messages">
|
<div class="game-messages">
|
||||||
<div v-if="gameMessage" class="game-message" :class="gameMessageType">
|
<div v-if="gameMessage" class="game-message" :class="gameMessageType">
|
||||||
{{ gameMessage }}
|
{{ gameMessage }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<div v-if="gameEnded" class="game-result-overlay">
|
<div v-if="gameEnded" class="game-result-overlay">
|
||||||
<div class="game-result">
|
<div class="game-result">
|
||||||
<h2>游戏结束</h2>
|
<h2>游戏结束</h2>
|
||||||
|
|
@ -179,16 +179,16 @@ function initPeer() {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
peer.value.on('open', (id) => {
|
peer.value.on('open', (id) => {
|
||||||
localPeerId.value = id;
|
localPeerId.value = id;
|
||||||
connectionStatus.value = '准备就绪,等待连接...';
|
connectionStatus.value = '准备就绪,等待连接...';
|
||||||
});
|
});
|
||||||
|
|
||||||
peer.value.on('connection', (conn) => {
|
peer.value.on('connection', (conn) => {
|
||||||
handleConnection(conn);
|
handleConnection(conn);
|
||||||
});
|
});
|
||||||
|
|
||||||
peer.value.on('error', (err) => {
|
peer.value.on('error', (err) => {
|
||||||
console.error('PeerJS错误:', err);
|
console.error('PeerJS错误:', err);
|
||||||
connectionStatus.value = `连接错误: ${err}`;
|
connectionStatus.value = `连接错误: ${err}`;
|
||||||
|
|
@ -199,14 +199,14 @@ function initPeer() {
|
||||||
// 连接到对方
|
// 连接到对方
|
||||||
function connectToPeer() {
|
function connectToPeer() {
|
||||||
if (!peer.value || !remotePeerId.value) return;
|
if (!peer.value || !remotePeerId.value) return;
|
||||||
|
|
||||||
connectionStatus.value = '正在连接...';
|
connectionStatus.value = '正在连接...';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const conn = peer.value.connect(remotePeerId.value, {
|
const conn = peer.value.connect(remotePeerId.value, {
|
||||||
reliable: true
|
reliable: true
|
||||||
});
|
});
|
||||||
|
|
||||||
handleConnection(conn);
|
handleConnection(conn);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('连接失败:', error);
|
console.error('连接失败:', error);
|
||||||
|
|
@ -217,22 +217,22 @@ function connectToPeer() {
|
||||||
// 处理连接
|
// 处理连接
|
||||||
function handleConnection(conn: DataConnection) {
|
function handleConnection(conn: DataConnection) {
|
||||||
connection.value = conn;
|
connection.value = conn;
|
||||||
|
|
||||||
conn.on('open', () => {
|
conn.on('open', () => {
|
||||||
isConnected.value = true;
|
isConnected.value = true;
|
||||||
connectionStatus.value = '连接成功!';
|
connectionStatus.value = '连接成功!';
|
||||||
showGameMessage('连接成功!', 'success');
|
showGameMessage('连接成功!', 'success');
|
||||||
|
|
||||||
// 如果是加入方,等待主机发送游戏设置
|
// 如果是加入方,等待主机发送游戏设置
|
||||||
if (mode.value === 'join') {
|
if (mode.value === 'join') {
|
||||||
localPlayerTurn.value = false;
|
localPlayerTurn.value = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
conn.on('data', (data: any) => {
|
conn.on('data', (data: any) => {
|
||||||
handleReceivedData(data);
|
handleReceivedData(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
conn.on('close', () => {
|
conn.on('close', () => {
|
||||||
isConnected.value = false;
|
isConnected.value = false;
|
||||||
connectionStatus.value = '连接已关闭';
|
connectionStatus.value = '连接已关闭';
|
||||||
|
|
@ -241,7 +241,7 @@ function handleConnection(conn: DataConnection) {
|
||||||
endGame();
|
endGame();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
conn.on('error', (err) => {
|
conn.on('error', (err) => {
|
||||||
console.error('连接错误:', err);
|
console.error('连接错误:', err);
|
||||||
connectionStatus.value = `连接错误: ${err}`;
|
connectionStatus.value = `连接错误: ${err}`;
|
||||||
|
|
@ -252,13 +252,13 @@ function handleConnection(conn: DataConnection) {
|
||||||
// 开始游戏
|
// 开始游戏
|
||||||
function startGame() {
|
function startGame() {
|
||||||
if (!isConnected.value || !connection.value) return;
|
if (!isConnected.value || !connection.value) return;
|
||||||
|
|
||||||
// 发送游戏设置给对方
|
// 发送游戏设置给对方
|
||||||
connection.value.send({
|
connection.value.send({
|
||||||
type: 'game-settings',
|
type: 'game-settings',
|
||||||
difficulty: selectedDifficulty.value
|
difficulty: selectedDifficulty.value
|
||||||
});
|
});
|
||||||
|
|
||||||
// 开始倒计时
|
// 开始倒计时
|
||||||
timeLeft.value = 30;
|
timeLeft.value = 30;
|
||||||
localScore.value = 0;
|
localScore.value = 0;
|
||||||
|
|
@ -266,13 +266,13 @@ function startGame() {
|
||||||
isGameActive.value = true;
|
isGameActive.value = true;
|
||||||
gameEnded.value = false;
|
gameEnded.value = false;
|
||||||
localPlayerTurn.value = mode.value === 'host'; // 主机先手
|
localPlayerTurn.value = mode.value === 'host'; // 主机先手
|
||||||
|
|
||||||
// 生成第一题
|
// 生成第一题
|
||||||
generateNewQuestion();
|
generateNewQuestion();
|
||||||
|
|
||||||
// 启动计时器
|
// 启动计时器
|
||||||
startTimer();
|
startTimer();
|
||||||
|
|
||||||
// 通知对方游戏已开始
|
// 通知对方游戏已开始
|
||||||
connection.value.send({
|
connection.value.send({
|
||||||
type: 'game-started'
|
type: 'game-started'
|
||||||
|
|
@ -283,7 +283,7 @@ function startGame() {
|
||||||
function generateNewQuestion() {
|
function generateNewQuestion() {
|
||||||
try {
|
try {
|
||||||
currentQuestion.value = generateQuestion(parseInt(selectedDifficulty.value));
|
currentQuestion.value = generateQuestion(parseInt(selectedDifficulty.value));
|
||||||
|
|
||||||
// 如果自己是当前回合玩家,发送题目给对方
|
// 如果自己是当前回合玩家,发送题目给对方
|
||||||
if (localPlayerTurn.value && connection.value) {
|
if (localPlayerTurn.value && connection.value) {
|
||||||
connection.value.send({
|
connection.value.send({
|
||||||
|
|
@ -301,17 +301,17 @@ function generateNewQuestion() {
|
||||||
// 提交答案
|
// 提交答案
|
||||||
function submitAnswer() {
|
function submitAnswer() {
|
||||||
if (!isGameActive.value || !localPlayerTurn.value) return;
|
if (!isGameActive.value || !localPlayerTurn.value) return;
|
||||||
|
|
||||||
const isCorrect = currentQuestion.value.answer.toString() === userAnswer.value;
|
const isCorrect = currentQuestion.value.answer.toString() === userAnswer.value;
|
||||||
lastCorrectAnswer.value = currentQuestion.value.answer.toString();
|
lastCorrectAnswer.value = currentQuestion.value.answer.toString();
|
||||||
|
|
||||||
if (isCorrect) {
|
if (isCorrect) {
|
||||||
localScore.value += 1;
|
localScore.value += 1;
|
||||||
answerFeedback.value = 'correct';
|
answerFeedback.value = 'correct';
|
||||||
} else {
|
} else {
|
||||||
answerFeedback.value = 'wrong';
|
answerFeedback.value = 'wrong';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送答题结果给对方
|
// 发送答题结果给对方
|
||||||
if (connection.value) {
|
if (connection.value) {
|
||||||
connection.value.send({
|
connection.value.send({
|
||||||
|
|
@ -320,14 +320,14 @@ function submitAnswer() {
|
||||||
score: localScore.value
|
score: localScore.value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 交换回合
|
// 交换回合
|
||||||
localPlayerTurn.value = false;
|
localPlayerTurn.value = false;
|
||||||
|
|
||||||
// 生成新题目给对方
|
// 生成新题目给对方
|
||||||
generateNewQuestion();
|
generateNewQuestion();
|
||||||
userAnswer.value = '';
|
userAnswer.value = '';
|
||||||
|
|
||||||
// 设置短暂的反馈后恢复
|
// 设置短暂的反馈后恢复
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
answerFeedback.value = 'none';
|
answerFeedback.value = 'none';
|
||||||
|
|
@ -337,14 +337,14 @@ function submitAnswer() {
|
||||||
// 启动计时器
|
// 启动计时器
|
||||||
function startTimer() {
|
function startTimer() {
|
||||||
clearTimerInterval();
|
clearTimerInterval();
|
||||||
|
|
||||||
timerInterval.value = window.setInterval(() => {
|
timerInterval.value = window.setInterval(() => {
|
||||||
timeLeft.value--;
|
timeLeft.value--;
|
||||||
|
|
||||||
if (timeLeft.value <= 0) {
|
if (timeLeft.value <= 0) {
|
||||||
clearTimerInterval();
|
clearTimerInterval();
|
||||||
endGame();
|
endGame();
|
||||||
|
|
||||||
// 通知对方游戏结束
|
// 通知对方游戏结束
|
||||||
if (connection.value) {
|
if (connection.value) {
|
||||||
connection.value.send({
|
connection.value.send({
|
||||||
|
|
@ -384,13 +384,13 @@ function resetGame() {
|
||||||
// 处理接收到的数据
|
// 处理接收到的数据
|
||||||
function handleReceivedData(data: any) {
|
function handleReceivedData(data: any) {
|
||||||
console.log('收到数据:', data);
|
console.log('收到数据:', data);
|
||||||
|
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case 'game-settings':
|
case 'game-settings':
|
||||||
// 接收到游戏设置
|
// 接收到游戏设置
|
||||||
selectedDifficulty.value = data.difficulty;
|
selectedDifficulty.value = data.difficulty;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'game-started':
|
case 'game-started':
|
||||||
// 游戏开始
|
// 游戏开始
|
||||||
isGameActive.value = true;
|
isGameActive.value = true;
|
||||||
|
|
@ -398,7 +398,7 @@ function handleReceivedData(data: any) {
|
||||||
timeLeft.value = 30;
|
timeLeft.value = 30;
|
||||||
startTimer();
|
startTimer();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'new-question':
|
case 'new-question':
|
||||||
// 接收到新题目
|
// 接收到新题目
|
||||||
currentQuestion.value = {
|
currentQuestion.value = {
|
||||||
|
|
@ -408,7 +408,7 @@ function handleReceivedData(data: any) {
|
||||||
// 接收到新题目意味着轮到我方回答
|
// 接收到新题目意味着轮到我方回答
|
||||||
localPlayerTurn.value = true;
|
localPlayerTurn.value = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'answer-result':
|
case 'answer-result':
|
||||||
// 对方答题结果
|
// 对方答题结果
|
||||||
remoteScore.value = data.score;
|
remoteScore.value = data.score;
|
||||||
|
|
@ -421,7 +421,7 @@ function handleReceivedData(data: any) {
|
||||||
localPlayerTurn.value = true;
|
localPlayerTurn.value = true;
|
||||||
generateNewQuestion();
|
generateNewQuestion();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'game-ended':
|
case 'game-ended':
|
||||||
// 游戏结束
|
// 游戏结束
|
||||||
endGame();
|
endGame();
|
||||||
|
|
@ -433,406 +433,11 @@ function handleReceivedData(data: any) {
|
||||||
function showGameMessage(message: string, type: 'success' | 'error' | 'info' = 'info') {
|
function showGameMessage(message: string, type: 'success' | 'error' | 'info' = 'info') {
|
||||||
gameMessage.value = message;
|
gameMessage.value = message;
|
||||||
gameMessageType.value = type;
|
gameMessageType.value = type;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
gameMessage.value = '';
|
gameMessage.value = '';
|
||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped src="../assets/network-bettle.css"></style>
|
||||||
.network-battle-page {
|
|
||||||
background: linear-gradient(135deg, #f7f9fc, #e2e7ed);
|
|
||||||
max-width: 800px;
|
|
||||||
margin: 2rem auto;
|
|
||||||
border-radius: 12px;
|
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|
||||||
text-align: center;
|
|
||||||
padding: 2rem;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.network-battle-page h1 {
|
|
||||||
font-size: 2.2rem;
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.connection-section {
|
|
||||||
background-color: rgba(255, 255, 255, 0.7);
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 1.5rem;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.connection-type {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 1rem;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.connection-type button {
|
|
||||||
background: rgba(255, 255, 255, 0.8);
|
|
||||||
color: #555;
|
|
||||||
border: 2px solid #ddd;
|
|
||||||
border-radius: 30px;
|
|
||||||
padding: 0.7rem 1.5rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: bold;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.connection-type button.active {
|
|
||||||
background: linear-gradient(90deg, #84b9ff, #32a8ff, #0faeff);
|
|
||||||
color: white;
|
|
||||||
border-color: transparent;
|
|
||||||
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.host-section, .join-section {
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.local-info {
|
|
||||||
background-color: rgba(255, 255, 255, 0.9);
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 1rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.peer-id {
|
|
||||||
font-weight: bold;
|
|
||||||
color: #0077cc;
|
|
||||||
background: rgba(0, 119, 204, 0.1);
|
|
||||||
padding: 0.3rem 0.6rem;
|
|
||||||
border-radius: 4px;
|
|
||||||
margin: 0 0.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.copy-button {
|
|
||||||
background: rgba(0, 119, 204, 0.1);
|
|
||||||
color: #0077cc;
|
|
||||||
border: 1px solid #0077cc;
|
|
||||||
border-radius: 20px;
|
|
||||||
padding: 0.3rem 0.8rem;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.copy-button:hover {
|
|
||||||
background: rgba(0, 119, 204, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-group {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-group label {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-group input {
|
|
||||||
padding: 0.8rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
border-radius: 20px;
|
|
||||||
border: 2px solid #ddd;
|
|
||||||
width: 80%;
|
|
||||||
max-width: 400px;
|
|
||||||
text-align: center;
|
|
||||||
outline: none;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-group input:focus {
|
|
||||||
border-color: #007ACC;
|
|
||||||
box-shadow: 0 0 0 2px rgba(0,122,204,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-settings {
|
|
||||||
margin: 1.5rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
margin-left: 1rem;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
padding: 0.6rem 1rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
border-radius: 20px;
|
|
||||||
border: 2px solid #ddd;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
color: #555;
|
|
||||||
cursor: pointer;
|
|
||||||
outline: none;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
select:focus {
|
|
||||||
border-color: #007ACC;
|
|
||||||
box-shadow: 0 0 0 2px rgba(0,122,204,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
background: linear-gradient(90deg, #84b9ff, #32a8ff, #0faeff);
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: 30px;
|
|
||||||
padding: 0.7rem 1.5rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: bold;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
|
||||||
margin: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover {
|
|
||||||
transform: translateY(-2px);
|
|
||||||
box-shadow: 0 6px 8px rgba(0,0,0,0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
button:disabled {
|
|
||||||
background: #cccccc;
|
|
||||||
cursor: not-allowed;
|
|
||||||
transform: none;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.players-info {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-around;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player {
|
|
||||||
background-color: rgba(255, 255, 255, 0.7);
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 1rem;
|
|
||||||
width: 45%;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
border: 2px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.player-turn {
|
|
||||||
border-color: #32a8ff;
|
|
||||||
background-color: rgba(50, 168, 255, 0.1);
|
|
||||||
box-shadow: 0 0 8px rgba(50, 168, 255, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.player h3 {
|
|
||||||
margin: 0 0 0.5rem 0;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.score {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 0.5rem 0;
|
|
||||||
color: #42b883;
|
|
||||||
}
|
|
||||||
|
|
||||||
.question-section p {
|
|
||||||
font-size: 1.8rem;
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 1.5rem 0;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.question-section input {
|
|
||||||
margin: 1rem 0;
|
|
||||||
padding: 0.8rem;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
border-radius: 20px;
|
|
||||||
border: 2px solid #ddd;
|
|
||||||
width: 200px;
|
|
||||||
text-align: center;
|
|
||||||
outline: none;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.question-section input:focus {
|
|
||||||
border-color: #007ACC;
|
|
||||||
box-shadow: 0 0 0 2px rgba(0,122,204,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.question-section input:disabled {
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.timer-section p {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #e74c3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.feedback-container {
|
|
||||||
height: 30px;
|
|
||||||
margin: 10px 0;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.feedback {
|
|
||||||
padding: 6px 12px;
|
|
||||||
border-radius: 20px;
|
|
||||||
display: inline-block;
|
|
||||||
font-weight: bold;
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.feedback.correct {
|
|
||||||
background-color: rgba(66, 184, 131, 0.2);
|
|
||||||
color: #2a8c5f;
|
|
||||||
border: 1px solid #42b883;
|
|
||||||
}
|
|
||||||
|
|
||||||
.feedback.wrong {
|
|
||||||
background-color: rgba(231, 76, 60, 0.2);
|
|
||||||
color: #c0392b;
|
|
||||||
border: 1px solid #e74c3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.correct-answer {
|
|
||||||
animation: pulse-green 0.5s;
|
|
||||||
border-color: #42b883 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrong-answer {
|
|
||||||
animation: pulse-red 0.5s;
|
|
||||||
border-color: #e74c3c !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-messages {
|
|
||||||
height: 40px;
|
|
||||||
margin: 1rem 0;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-message {
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
border-radius: 20px;
|
|
||||||
font-weight: bold;
|
|
||||||
animation: fade-in 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-message.success {
|
|
||||||
background-color: rgba(66, 184, 131, 0.2);
|
|
||||||
color: #2a8c5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-message.error {
|
|
||||||
background-color: rgba(231, 76, 60, 0.2);
|
|
||||||
color: #c0392b;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-message.info {
|
|
||||||
background-color: rgba(52, 152, 219, 0.2);
|
|
||||||
color: #2980b9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-result-overlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background-color: rgba(0, 0, 0, 0.7);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
z-index: 10;
|
|
||||||
animation: fade-in 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-result {
|
|
||||||
background-color: white;
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 2rem;
|
|
||||||
width: 90%;
|
|
||||||
max-width: 500px;
|
|
||||||
text-align: center;
|
|
||||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-result h2 {
|
|
||||||
font-size: 2rem;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.final-scores {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-around;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.final-scores p {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.result-message {
|
|
||||||
font-size: 2rem;
|
|
||||||
margin: 1.5rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.result-message.win {
|
|
||||||
color: #42b883;
|
|
||||||
}
|
|
||||||
|
|
||||||
.result-message.lose {
|
|
||||||
color: #e74c3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.result-message.draw {
|
|
||||||
color: #f39c12;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 动画效果 */
|
|
||||||
.fade-enter-active,
|
|
||||||
.fade-leave-active {
|
|
||||||
transition: opacity 0.5s, transform 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fade-enter-from,
|
|
||||||
.fade-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-10px) translateX(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes pulse-green {
|
|
||||||
0% { box-shadow: 0 0 0 0 rgba(66, 184, 131, 0.7); }
|
|
||||||
70% { box-shadow: 0 0 0 10px rgba(66, 184, 131, 0); }
|
|
||||||
100% { box-shadow: 0 0 0 0 rgba(66, 184, 131, 0); }
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes pulse-red {
|
|
||||||
0% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0.7); }
|
|
||||||
70% { box-shadow: 0 0 0 10px rgba(231, 76, 60, 0); }
|
|
||||||
100% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0); }
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fade-in {
|
|
||||||
from { opacity: 0; }
|
|
||||||
to { opacity: 1; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -147,225 +147,4 @@ onUnmounted(() => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped src="../assets/practice.css"></style>
|
||||||
.practice-page {
|
|
||||||
background: linear-gradient(135deg, #f7f9fc, #e2e7ed);
|
|
||||||
max-width: 800px;
|
|
||||||
margin: 2rem auto;
|
|
||||||
border-radius: 12px;
|
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|
||||||
text-align: center;
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.practice-page h1 {
|
|
||||||
font-size: 2.2rem;
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
header label {
|
|
||||||
margin-left: 1rem;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
header select {
|
|
||||||
padding: 0.6rem 1rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
border-radius: 20px;
|
|
||||||
border: 2px solid #ddd;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
color: #555;
|
|
||||||
cursor: pointer;
|
|
||||||
outline: none;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
header select:focus {
|
|
||||||
border-color: #007ACC;
|
|
||||||
box-shadow: 0 0 0 2px rgba(0,122,204,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
background: linear-gradient(90deg, #84b9ff, #32a8ff, #0faeff);
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: 30px;
|
|
||||||
padding: 0.7rem 1.5rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: bold;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
|
||||||
margin: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover {
|
|
||||||
transform: translateY(-2px);
|
|
||||||
box-shadow: 0 6px 8px rgba(0,0,0,0.15);
|
|
||||||
background: linear-gradient(90deg, #84b9ff, #32a8ff, #0faeff);
|
|
||||||
}
|
|
||||||
|
|
||||||
header button {
|
|
||||||
margin-top: 1.5rem;
|
|
||||||
padding: 0.7rem 1.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.question-section p {
|
|
||||||
font-size: 1.8rem;
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 1.5rem 0;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.question-section input {
|
|
||||||
margin: 1rem 0;
|
|
||||||
padding: 0.8rem;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
border-radius: 20px;
|
|
||||||
border: 2px solid #ddd;
|
|
||||||
width: 200px;
|
|
||||||
text-align: center;
|
|
||||||
outline: none;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.question-section input:focus {
|
|
||||||
border-color: #007ACC;
|
|
||||||
box-shadow: 0 0 0 2px rgba(0,122,204,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.timer-section p {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #e74c3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.score-section p {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #42b883;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
margin-top: 2rem;
|
|
||||||
padding-top: 1.5rem;
|
|
||||||
border-top: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer p {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #555;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer ul {
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0;
|
|
||||||
margin: 1rem 0;
|
|
||||||
max-height: 300px;
|
|
||||||
overflow-y: auto;
|
|
||||||
/* 移除背景色和内边距,使其更扁平 */
|
|
||||||
background-color: transparent;
|
|
||||||
border-radius: 0;
|
|
||||||
padding: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer li {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0.8rem 1rem;
|
|
||||||
background-color: rgba(255, 255, 255, 0.7);
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
border-left: 3px solid #32a8ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer li:hover {
|
|
||||||
background-color: white;
|
|
||||||
transform: translateX(2px);
|
|
||||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
footer button {
|
|
||||||
background: linear-gradient(90deg, #ff7675, #d63031);
|
|
||||||
margin-top: 1.5rem;
|
|
||||||
padding: 0.6rem 1.4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer button:hover {
|
|
||||||
background: linear-gradient(90deg, #ff6b6b, #c0392b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 答题反馈动画 */
|
|
||||||
.feedback-container {
|
|
||||||
height: 30px;
|
|
||||||
margin: 10px 0;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.feedback {
|
|
||||||
padding: 6px 12px;
|
|
||||||
border-radius: 20px;
|
|
||||||
display: inline-block;
|
|
||||||
font-weight: bold;
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.feedback.correct {
|
|
||||||
background-color: rgba(66, 184, 131, 0.2);
|
|
||||||
color: #2a8c5f;
|
|
||||||
border: 1px solid #42b883;
|
|
||||||
}
|
|
||||||
|
|
||||||
.feedback.wrong {
|
|
||||||
background-color: rgba(231, 76, 60, 0.2);
|
|
||||||
color: #c0392b;
|
|
||||||
border: 1px solid #e74c3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 输入框的反馈效果 */
|
|
||||||
.correct-answer {
|
|
||||||
animation: pulse-green 0.5s;
|
|
||||||
border-color: #42b883 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrong-answer {
|
|
||||||
animation: pulse-red 0.5s;
|
|
||||||
border-color: #e74c3c !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 淡入淡出动画 */
|
|
||||||
.fade-enter-active,
|
|
||||||
.fade-leave-active {
|
|
||||||
transition: opacity 0.5s, transform 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fade-enter-from,
|
|
||||||
.fade-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-10px) translateX(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 脉动动画效果 */
|
|
||||||
@keyframes pulse-green {
|
|
||||||
0% { box-shadow: 0 0 0 0 rgba(66, 184, 131, 0.7); }
|
|
||||||
70% { box-shadow: 0 0 0 10px rgba(66, 184, 131, 0); }
|
|
||||||
100% { box-shadow: 0 0 0 0 rgba(66, 184, 131, 0); }
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes pulse-red {
|
|
||||||
0% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0.7); }
|
|
||||||
70% { box-shadow: 0 0 0 10px rgba(231, 76, 60, 0); }
|
|
||||||
100% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0); }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue