优化结果
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
/* 背景样式文件 */
|
||||
|
||||
/* 主体背景 */
|
||||
body {
|
||||
background: linear-gradient(135deg, #e8f5e8 0%, #c8e6c9 50%, #a5d6a7 100%);
|
||||
background-attachment: fixed;
|
||||
background-size: 400% 400%;
|
||||
animation: gradientShift 15s ease infinite;
|
||||
}
|
||||
|
||||
/* 背景动画 */
|
||||
@keyframes gradientShift {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
/* 装饰性背景元素 */
|
||||
body::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image:
|
||||
radial-gradient(circle at 20% 80%, rgba(76, 175, 80, 0.1) 0%, transparent 50%),
|
||||
radial-gradient(circle at 80% 20%, rgba(129, 199, 132, 0.1) 0%, transparent 50%),
|
||||
radial-gradient(circle at 40% 40%, rgba(165, 214, 167, 0.08) 0%, transparent 50%);
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
/* 浮动装饰圆点 */
|
||||
body::after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image:
|
||||
radial-gradient(2px 2px at 20px 30px, rgba(76, 175, 80, 0.3), transparent),
|
||||
radial-gradient(2px 2px at 40px 70px, rgba(129, 199, 132, 0.2), transparent),
|
||||
radial-gradient(1px 1px at 90px 40px, rgba(165, 214, 167, 0.3), transparent),
|
||||
radial-gradient(1px 1px at 130px 80px, rgba(76, 175, 80, 0.2), transparent),
|
||||
radial-gradient(2px 2px at 160px 30px, rgba(129, 199, 132, 0.3), transparent);
|
||||
background-repeat: repeat;
|
||||
background-size: 200px 100px;
|
||||
animation: float 20s linear infinite;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
}
|
||||
|
||||
/* 题目容器背景增强 */
|
||||
.question-container {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
box-shadow:
|
||||
0 8px 32px rgba(26, 77, 26, 0.1),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
/* 错误容器背景 */
|
||||
.error-container {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
/* 结果容器背景 */
|
||||
.result-container {
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
backdrop-filter: blur(5px);
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
/* 代码块背景 */
|
||||
.code-block {
|
||||
background: rgba(248, 249, 250, 0.9);
|
||||
backdrop-filter: blur(5px);
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
/* 选项背景 */
|
||||
.option {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
backdrop-filter: blur(5px);
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
.option:hover {
|
||||
background: rgba(76, 175, 80, 0.05);
|
||||
}
|
||||
|
||||
.option.selected {
|
||||
background: linear-gradient(135deg, rgba(76, 175, 80, 0.15), rgba(76, 175, 80, 0.08));
|
||||
}
|
||||
|
||||
/* 按钮背景增强 */
|
||||
.submit-btn {
|
||||
background: linear-gradient(135deg, #4caf50, #45a049);
|
||||
box-shadow: 0 4px 15px rgba(76, 175, 80, 0.2);
|
||||
}
|
||||
|
||||
.show-answer-btn {
|
||||
background: linear-gradient(135deg, #2196f3, #1976d2);
|
||||
box-shadow: 0 4px 15px rgba(33, 150, 243, 0.2);
|
||||
}
|
||||
|
||||
.retry-btn {
|
||||
background: linear-gradient(135deg, #ff9800, #f57c00);
|
||||
box-shadow: 0 4px 15px rgba(255, 152, 0, 0.2);
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
background: linear-gradient(135deg, #4caf50, #45a049);
|
||||
box-shadow: 0 4px 15px rgba(76, 175, 80, 0.2);
|
||||
}
|
||||
|
||||
/* 移动端背景优化 */
|
||||
@media (max-width: 768px) {
|
||||
body {
|
||||
background-attachment: scroll;
|
||||
}
|
||||
|
||||
body::after {
|
||||
opacity: 0.4;
|
||||
background-size: 150px 75px;
|
||||
}
|
||||
|
||||
.question-container {
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
}
|
||||
}
|
||||
|
||||
/* 高对比度模式支持 */
|
||||
@media (prefers-contrast: high) {
|
||||
body {
|
||||
background: #f0f8f0;
|
||||
}
|
||||
|
||||
body::before,
|
||||
body::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.question-container {
|
||||
background: #ffffff;
|
||||
border: 2px solid #4caf50;
|
||||
}
|
||||
}
|
||||
|
||||
/* 减少动画模式支持 */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
body {
|
||||
animation: none;
|
||||
background: #e8f5e8;
|
||||
}
|
||||
|
||||
body::after {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
.refresh-btn:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,597 @@
|
||||
/* 基础样式重置 */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #2d5a27;
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* 容器布局 */
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 头部样式 */
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
padding: 30px 0;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.5rem;
|
||||
color: #1a4d1a;
|
||||
margin-bottom: 10px;
|
||||
font-weight: 700;
|
||||
text-shadow: 0 2px 4px rgba(26, 77, 26, 0.1);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1.1rem;
|
||||
color: #4a7c59;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* 主内容区域 */
|
||||
.main-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
/* 加载动画 */
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 4px solid #e8f5e8;
|
||||
border-top: 4px solid #4caf50;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0 auto 20px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.loading p {
|
||||
color: #4a7c59;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
/* 题目容器 */
|
||||
.question-container {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 20px;
|
||||
padding: 40px;
|
||||
box-shadow: 0 10px 30px rgba(26, 77, 26, 0.1);
|
||||
border: 2px solid rgba(76, 175, 80, 0.2);
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
/* 题目头部 */
|
||||
.question-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 2px solid #e8f5e8;
|
||||
}
|
||||
|
||||
.question-id {
|
||||
font-size: 1.1rem;
|
||||
color: #4caf50;
|
||||
font-weight: 600;
|
||||
background: linear-gradient(135deg, #e8f5e8, #c8e6c9);
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
background: linear-gradient(135deg, #4caf50, #45a049);
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.refresh-btn:hover {
|
||||
transform: rotate(180deg) scale(1.1);
|
||||
box-shadow: 0 5px 15px rgba(76, 175, 80, 0.3);
|
||||
}
|
||||
|
||||
/* 题目文本 */
|
||||
.question-text h2 {
|
||||
font-size: 1.5rem;
|
||||
color: #1a4d1a;
|
||||
margin-bottom: 25px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 代码块 */
|
||||
.code-block {
|
||||
background: #f8f9fa;
|
||||
border: 2px solid #e8f5e8;
|
||||
border-radius: 12px;
|
||||
margin: 25px 0;
|
||||
overflow-x: auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.code-block pre {
|
||||
margin: 0;
|
||||
padding: 25px;
|
||||
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.5;
|
||||
color: #2d5a27;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.code-block code {
|
||||
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
/* 代码高亮自定义样式 - 丰富的语法高亮 */
|
||||
.code-block .hljs {
|
||||
background: transparent !important;
|
||||
color: #333333 !important;
|
||||
}
|
||||
|
||||
/* JavaScript 关键字 - 蓝色 */
|
||||
.code-block .hljs-keyword {
|
||||
color: #0066cc !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 字符串 - 绿色 */
|
||||
.code-block .hljs-string {
|
||||
color: #22aa22 !important;
|
||||
}
|
||||
|
||||
/* 数字 - 橙色 */
|
||||
.code-block .hljs-number {
|
||||
color: #ff6600 !important;
|
||||
}
|
||||
|
||||
/* 函数名 - 紫色 */
|
||||
.code-block .hljs-function,
|
||||
.code-block .hljs-title.function_ {
|
||||
color: #9933cc !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 变量名 - 深蓝色 */
|
||||
.code-block .hljs-variable,
|
||||
.code-block .hljs-name {
|
||||
color: #0066aa !important;
|
||||
}
|
||||
|
||||
/* 注释 - 灰色 */
|
||||
.code-block .hljs-comment {
|
||||
color: #888888 !important;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* 内置对象和方法 - 深紫色 */
|
||||
.code-block .hljs-built_in {
|
||||
color: #663399 !important;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 字面量 (true, false, null) - 红色 */
|
||||
.code-block .hljs-literal {
|
||||
color: #cc0000 !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 操作符 - 深灰色 */
|
||||
.code-block .hljs-operator {
|
||||
color: #666666 !important;
|
||||
}
|
||||
|
||||
/* 标点符号 - 深灰色 */
|
||||
.code-block .hljs-punctuation {
|
||||
color: #666666 !important;
|
||||
}
|
||||
|
||||
/* 属性名 - 深蓝色 */
|
||||
.code-block .hljs-property,
|
||||
.code-block .hljs-attr {
|
||||
color: #0066aa !important;
|
||||
}
|
||||
|
||||
/* 类名和构造函数 - 深绿色 */
|
||||
.code-block .hljs-title.class_,
|
||||
.code-block .hljs-title {
|
||||
color: #228833 !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 参数 - 深蓝色 */
|
||||
.code-block .hljs-params {
|
||||
color: #0066aa !important;
|
||||
}
|
||||
|
||||
/* 正则表达式 - 深红色 */
|
||||
.code-block .hljs-regexp {
|
||||
color: #aa0066 !important;
|
||||
}
|
||||
|
||||
/* 模板字符串 - 深绿色 */
|
||||
.code-block .hljs-template-variable,
|
||||
.code-block .hljs-template-tag {
|
||||
color: #228833 !important;
|
||||
}
|
||||
|
||||
/* 选项容器 */
|
||||
.options-container {
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
.option {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
border: 2px solid #e8f5e8;
|
||||
border-radius: 12px;
|
||||
padding: 15px 20px;
|
||||
margin: 12px 0;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
font-size: 1rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.option:hover {
|
||||
border-color: #4caf50;
|
||||
background: rgba(76, 175, 80, 0.05);
|
||||
transform: translateX(5px);
|
||||
}
|
||||
|
||||
.option.selected {
|
||||
border-color: #4caf50;
|
||||
background: linear-gradient(135deg, rgba(76, 175, 80, 0.1), rgba(76, 175, 80, 0.05));
|
||||
color: #1a4d1a;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.option.correct {
|
||||
border-color: #4caf50;
|
||||
background: linear-gradient(135deg, rgba(76, 175, 80, 0.2), rgba(76, 175, 80, 0.1));
|
||||
color: #1a4d1a;
|
||||
}
|
||||
|
||||
.option.incorrect {
|
||||
border-color: #f44336;
|
||||
background: linear-gradient(135deg, rgba(244, 67, 54, 0.1), rgba(244, 67, 54, 0.05));
|
||||
color: #c62828;
|
||||
}
|
||||
|
||||
/* 按钮样式 */
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
margin: 30px 0;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.submit-btn, .show-answer-btn, .retry-btn, .export-btn {
|
||||
padding: 12px 30px;
|
||||
border: none;
|
||||
border-radius: 25px;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
min-width: 120px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
background: linear-gradient(135deg, #4caf50, #45a049);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.submit-btn:hover:not(:disabled) {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(76, 175, 80, 0.3);
|
||||
}
|
||||
|
||||
.submit-btn:disabled {
|
||||
background: #cccccc;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.show-answer-btn {
|
||||
background: linear-gradient(135deg, #2196f3, #1976d2);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.show-answer-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(33, 150, 243, 0.3);
|
||||
}
|
||||
|
||||
.retry-btn {
|
||||
background: linear-gradient(135deg, #ff9800, #f57c00);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.retry-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(255, 152, 0, 0.3);
|
||||
}
|
||||
|
||||
.export-btn {
|
||||
background: linear-gradient(135deg, #9c27b0, #7b1fa2);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.export-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(156, 39, 176, 0.3);
|
||||
}
|
||||
|
||||
.export-btn svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
/* 结果容器 */
|
||||
.result-container {
|
||||
margin-top: 30px;
|
||||
padding: 25px;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border-radius: 15px;
|
||||
border: 2px solid #e8f5e8;
|
||||
}
|
||||
|
||||
.result-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid #e8f5e8;
|
||||
}
|
||||
|
||||
.result-status {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.result-status.correct {
|
||||
color: #4caf50;
|
||||
}
|
||||
|
||||
.result-status.incorrect {
|
||||
color: #f44336;
|
||||
}
|
||||
|
||||
.correct-answer {
|
||||
font-weight: 600;
|
||||
color: #4caf50;
|
||||
background: rgba(76, 175, 80, 0.1);
|
||||
padding: 5px 12px;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.explanation {
|
||||
color: #2d5a27;
|
||||
line-height: 1.7;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.explanation pre {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e8f5e8;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
margin: 15px 0;
|
||||
overflow-x: auto;
|
||||
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
||||
}
|
||||
|
||||
/* 错误容器 */
|
||||
.error-container {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border-radius: 20px;
|
||||
border: 2px solid rgba(244, 67, 54, 0.2);
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.error-icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.error-container h3 {
|
||||
color: #f44336;
|
||||
margin-bottom: 15px;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.error-container p {
|
||||
color: #666;
|
||||
margin-bottom: 25px;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
/* 底部 */
|
||||
.footer {
|
||||
text-align: center;
|
||||
padding: 30px 0;
|
||||
margin-top: 40px;
|
||||
color: #4a7c59;
|
||||
opacity: 0.7;
|
||||
border-top: 1px solid rgba(76, 175, 80, 0.2);
|
||||
}
|
||||
|
||||
/* 平板端适配 (768px - 1024px) */
|
||||
@media (max-width: 1024px) and (min-width: 768px) {
|
||||
.container {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2.2rem;
|
||||
}
|
||||
|
||||
.question-container {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
/* 手机端适配 (最大768px) */
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 25px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.question-container {
|
||||
padding: 20px;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.question-header {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.question-text h2 {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.code-block pre {
|
||||
padding: 15px;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.option {
|
||||
padding: 12px 15px;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.submit-btn, .show-answer-btn, .retry-btn {
|
||||
width: 100%;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.result-header {
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.explanation {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.explanation pre {
|
||||
padding: 10px;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 小屏手机适配 (最大480px) */
|
||||
@media (max-width: 480px) {
|
||||
.container {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
.question-container {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.question-id {
|
||||
font-size: 1rem;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.code-block pre {
|
||||
font-size: 0.8rem;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.option {
|
||||
padding: 10px 12px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.submit-btn, .show-answer-btn, .retry-btn {
|
||||
padding: 10px 20px;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>随机JavaScript趣味题</title>
|
||||
<link rel="preconnect" href="https://cdnjs.cloudflare.com">
|
||||
<link rel="dns-prefetch" href="https://60s.api.shumengya.top">
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<link rel="stylesheet" href="css/background.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/javascript.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header class="header">
|
||||
<h1>JavaScript趣味题</h1>
|
||||
<p class="subtitle">测试你的JavaScript知识</p>
|
||||
</header>
|
||||
|
||||
<main class="main-content">
|
||||
<div class="loading" id="loading">
|
||||
<div class="spinner"></div>
|
||||
<p>正在加载题目...</p>
|
||||
</div>
|
||||
|
||||
<div class="question-container" id="questionContainer" style="display: none;">
|
||||
<div class="question-header">
|
||||
<span class="question-id" id="questionId">题目 #1</span>
|
||||
<button class="refresh-btn" id="refreshBtn" title="获取新题目">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="23 4 23 10 17 10"></polyline>
|
||||
<polyline points="1 20 1 14 7 14"></polyline>
|
||||
<path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="question-text" id="questionText">
|
||||
<h2>输出是什么?</h2>
|
||||
</div>
|
||||
|
||||
<div class="code-block" id="codeBlock">
|
||||
<pre><code id="codeContent" class="language-javascript"></code></pre>
|
||||
</div>
|
||||
|
||||
<div class="options-container" id="optionsContainer">
|
||||
<!-- 选项将通过JavaScript动态生成 -->
|
||||
</div>
|
||||
|
||||
<div class="action-buttons">
|
||||
<button class="submit-btn" id="submitBtn" disabled>提交答案</button>
|
||||
<button class="show-answer-btn" id="showAnswerBtn">查看答案</button>
|
||||
<button class="export-btn" id="exportBtn" title="导出为Markdown文件">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
||||
<polyline points="7 10 12 15 17 10"></polyline>
|
||||
<line x1="12" y1="15" x2="12" y2="3"></line>
|
||||
</svg>
|
||||
导出MD
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="result-container" id="resultContainer" style="display: none;">
|
||||
<div class="result-header">
|
||||
<span class="result-status" id="resultStatus"></span>
|
||||
<span class="correct-answer" id="correctAnswer"></span>
|
||||
</div>
|
||||
<div class="explanation" id="explanation">
|
||||
<!-- 解析内容 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="error-container" id="errorContainer" style="display: none;">
|
||||
<div class="error-icon">⚠️</div>
|
||||
<h3>加载失败</h3>
|
||||
<p id="errorMessage">网络连接异常,请稍后重试</p>
|
||||
<button class="retry-btn" id="retryBtn">重新加载</button>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
<p>JavaScript趣味题集合</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<script src="js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,582 @@
|
||||
// JavaScript趣味题应用
|
||||
class JSQuizApp {
|
||||
constructor() {
|
||||
this.apiEndpoints = [
|
||||
'https://60s.api.shumengya.top',
|
||||
];
|
||||
this.currentApiIndex = 0;
|
||||
this.currentQuestion = null;
|
||||
this.selectedOption = null;
|
||||
this.isAnswered = false;
|
||||
this.loadStartTime = null;
|
||||
|
||||
this.initElements();
|
||||
this.bindEvents();
|
||||
this.preloadResources();
|
||||
this.loadQuestion();
|
||||
}
|
||||
|
||||
// 初始化DOM元素
|
||||
initElements() {
|
||||
this.elements = {
|
||||
loading: document.getElementById('loading'),
|
||||
questionContainer: document.getElementById('questionContainer'),
|
||||
errorContainer: document.getElementById('errorContainer'),
|
||||
questionId: document.getElementById('questionId'),
|
||||
questionText: document.getElementById('questionText'),
|
||||
codeContent: document.getElementById('codeContent'),
|
||||
optionsContainer: document.getElementById('optionsContainer'),
|
||||
submitBtn: document.getElementById('submitBtn'),
|
||||
showAnswerBtn: document.getElementById('showAnswerBtn'),
|
||||
refreshBtn: document.getElementById('refreshBtn'),
|
||||
retryBtn: document.getElementById('retryBtn'),
|
||||
exportBtn: document.getElementById('exportBtn'),
|
||||
resultContainer: document.getElementById('resultContainer'),
|
||||
resultStatus: document.getElementById('resultStatus'),
|
||||
correctAnswer: document.getElementById('correctAnswer'),
|
||||
explanation: document.getElementById('explanation'),
|
||||
errorMessage: document.getElementById('errorMessage')
|
||||
};
|
||||
}
|
||||
|
||||
// 预加载资源
|
||||
preloadResources() {
|
||||
// 预连接API服务器
|
||||
this.apiEndpoints.forEach(endpoint => {
|
||||
const link = document.createElement('link');
|
||||
link.rel = 'preconnect';
|
||||
link.href = endpoint;
|
||||
document.head.appendChild(link);
|
||||
});
|
||||
}
|
||||
|
||||
// 绑定事件
|
||||
bindEvents() {
|
||||
this.elements.submitBtn.addEventListener('click', () => this.submitAnswer());
|
||||
this.elements.showAnswerBtn.addEventListener('click', () => this.showAnswer());
|
||||
this.elements.refreshBtn.addEventListener('click', () => this.loadQuestion());
|
||||
this.elements.retryBtn.addEventListener('click', () => this.loadQuestion());
|
||||
this.elements.exportBtn.addEventListener('click', () => this.exportToMarkdown());
|
||||
}
|
||||
|
||||
// 显示加载状态
|
||||
showLoading() {
|
||||
this.elements.loading.style.display = 'block';
|
||||
this.elements.questionContainer.style.display = 'none';
|
||||
this.elements.errorContainer.style.display = 'none';
|
||||
}
|
||||
|
||||
// 显示题目
|
||||
showQuestion() {
|
||||
this.elements.loading.style.display = 'none';
|
||||
this.elements.questionContainer.style.display = 'block';
|
||||
this.elements.errorContainer.style.display = 'none';
|
||||
}
|
||||
|
||||
// 显示错误
|
||||
showError(message) {
|
||||
this.elements.loading.style.display = 'none';
|
||||
this.elements.questionContainer.style.display = 'none';
|
||||
this.elements.errorContainer.style.display = 'block';
|
||||
this.elements.errorMessage.textContent = message;
|
||||
}
|
||||
|
||||
// 获取当前API地址
|
||||
getCurrentApiUrl() {
|
||||
return `${this.apiEndpoints[this.currentApiIndex]}/v2/awesome-js`;
|
||||
}
|
||||
|
||||
// 切换到下一个API
|
||||
switchToNextApi() {
|
||||
this.currentApiIndex = (this.currentApiIndex + 1) % this.apiEndpoints.length;
|
||||
}
|
||||
|
||||
// 加载题目
|
||||
async loadQuestion() {
|
||||
this.loadStartTime = Date.now();
|
||||
this.showLoading();
|
||||
this.resetQuestion();
|
||||
|
||||
let attempts = 0;
|
||||
const maxAttempts = this.apiEndpoints.length;
|
||||
|
||||
while (attempts < maxAttempts) {
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), 5000);
|
||||
|
||||
const response = await fetch(this.getCurrentApiUrl(), {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
signal: controller.signal
|
||||
});
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.code === 200 && data.data) {
|
||||
this.currentQuestion = data.data;
|
||||
const loadTime = Date.now() - this.loadStartTime;
|
||||
console.log(`题目加载完成,耗时: ${loadTime}ms`);
|
||||
this.displayQuestion();
|
||||
return;
|
||||
} else {
|
||||
throw new Error(data.message || '数据格式错误');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.warn(`API ${this.getCurrentApiUrl()} 请求失败:`, error.message);
|
||||
attempts++;
|
||||
|
||||
if (attempts < maxAttempts) {
|
||||
this.switchToNextApi();
|
||||
console.log(`切换到备用API: ${this.getCurrentApiUrl()}`);
|
||||
} else {
|
||||
this.showError(`所有API接口都无法访问,请检查网络连接后重试。\n最后尝试的错误: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 重置题目状态
|
||||
resetQuestion() {
|
||||
this.selectedOption = null;
|
||||
this.isAnswered = false;
|
||||
this.elements.resultContainer.style.display = 'none';
|
||||
this.elements.submitBtn.disabled = true;
|
||||
this.elements.submitBtn.textContent = '提交答案';
|
||||
this.elements.showAnswerBtn.style.display = 'inline-block';
|
||||
|
||||
// 清空选项容器,防止重复显示
|
||||
this.elements.optionsContainer.innerHTML = '';
|
||||
|
||||
// 移除所有选项的事件监听器
|
||||
const existingOptions = document.querySelectorAll('.option');
|
||||
existingOptions.forEach(option => {
|
||||
option.removeEventListener('click', this.selectOption);
|
||||
});
|
||||
}
|
||||
|
||||
// 显示题目内容
|
||||
displayQuestion() {
|
||||
const question = this.currentQuestion;
|
||||
|
||||
console.log('显示题目:', question);
|
||||
|
||||
// 设置题目ID
|
||||
this.elements.questionId.textContent = `题目 #${question.id}`;
|
||||
|
||||
// 设置题目文本
|
||||
this.elements.questionText.innerHTML = `<h2>${this.escapeHtml(question.question)}</h2>`;
|
||||
|
||||
// 设置代码内容并应用语法高亮
|
||||
this.elements.codeContent.textContent = question.code;
|
||||
|
||||
// 应用语法高亮
|
||||
if (typeof hljs !== 'undefined') {
|
||||
hljs.highlightElement(this.elements.codeContent);
|
||||
}
|
||||
|
||||
// 确保选项容器已清空
|
||||
this.elements.optionsContainer.innerHTML = '';
|
||||
|
||||
// 生成选项
|
||||
this.generateOptions(question.options);
|
||||
|
||||
this.showQuestion();
|
||||
}
|
||||
|
||||
// 生成选项
|
||||
generateOptions(options) {
|
||||
// 确保清空容器
|
||||
this.elements.optionsContainer.innerHTML = '';
|
||||
|
||||
// 验证选项数据
|
||||
if (!Array.isArray(options) || options.length === 0) {
|
||||
console.error('选项数据无效:', options);
|
||||
return;
|
||||
}
|
||||
|
||||
// 移除可能存在的重复选项
|
||||
const uniqueOptions = [...new Set(options)];
|
||||
|
||||
uniqueOptions.forEach((option, index) => {
|
||||
const optionElement = document.createElement('div');
|
||||
optionElement.className = 'option';
|
||||
optionElement.textContent = option;
|
||||
optionElement.dataset.index = index;
|
||||
optionElement.dataset.value = option.charAt(0); // A, B, C, D
|
||||
|
||||
optionElement.addEventListener('click', () => this.selectOption(optionElement));
|
||||
|
||||
this.elements.optionsContainer.appendChild(optionElement);
|
||||
});
|
||||
|
||||
console.log('生成选项:', uniqueOptions);
|
||||
}
|
||||
|
||||
// 选择选项
|
||||
selectOption(optionElement) {
|
||||
if (this.isAnswered) return;
|
||||
|
||||
// 移除之前的选中状态
|
||||
document.querySelectorAll('.option.selected').forEach(el => {
|
||||
el.classList.remove('selected');
|
||||
});
|
||||
|
||||
// 设置当前选中
|
||||
optionElement.classList.add('selected');
|
||||
this.selectedOption = optionElement.dataset.value;
|
||||
|
||||
// 启用提交按钮
|
||||
this.elements.submitBtn.disabled = false;
|
||||
}
|
||||
|
||||
// 提交答案
|
||||
submitAnswer() {
|
||||
if (!this.selectedOption || this.isAnswered) return;
|
||||
|
||||
this.isAnswered = true;
|
||||
this.elements.submitBtn.disabled = true;
|
||||
this.elements.submitBtn.textContent = '已提交';
|
||||
this.elements.showAnswerBtn.style.display = 'none';
|
||||
|
||||
const isCorrect = this.selectedOption === this.currentQuestion.answer;
|
||||
|
||||
// 显示结果
|
||||
this.showResult(isCorrect);
|
||||
|
||||
// 标记选项
|
||||
this.markOptions();
|
||||
}
|
||||
|
||||
// 显示答案
|
||||
showAnswer() {
|
||||
this.isAnswered = true;
|
||||
this.elements.submitBtn.disabled = true;
|
||||
this.elements.submitBtn.textContent = '已显示答案';
|
||||
this.elements.showAnswerBtn.style.display = 'none';
|
||||
|
||||
// 显示结果(不判断对错)
|
||||
this.showResult(null);
|
||||
|
||||
// 标记正确答案
|
||||
this.markCorrectAnswer();
|
||||
}
|
||||
|
||||
// 显示结果
|
||||
showResult(isCorrect) {
|
||||
const resultContainer = this.elements.resultContainer;
|
||||
const resultStatus = this.elements.resultStatus;
|
||||
const correctAnswer = this.elements.correctAnswer;
|
||||
const explanation = this.elements.explanation;
|
||||
|
||||
// 设置结果状态
|
||||
if (isCorrect === true) {
|
||||
resultStatus.textContent = '✅ 回答正确!';
|
||||
resultStatus.className = 'result-status correct';
|
||||
} else if (isCorrect === false) {
|
||||
resultStatus.textContent = '❌ 回答错误';
|
||||
resultStatus.className = 'result-status incorrect';
|
||||
} else {
|
||||
resultStatus.textContent = '💡 答案解析';
|
||||
resultStatus.className = 'result-status';
|
||||
}
|
||||
|
||||
// 设置正确答案
|
||||
correctAnswer.textContent = `正确答案: ${this.currentQuestion.answer}`;
|
||||
|
||||
// 设置解析内容
|
||||
explanation.innerHTML = this.formatExplanation(this.currentQuestion.explanation);
|
||||
|
||||
// 显示结果容器
|
||||
resultContainer.style.display = 'block';
|
||||
|
||||
// 滚动到结果区域
|
||||
setTimeout(() => {
|
||||
resultContainer.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// 标记选项
|
||||
markOptions() {
|
||||
const options = document.querySelectorAll('.option');
|
||||
const correctAnswer = this.currentQuestion.answer;
|
||||
|
||||
options.forEach(option => {
|
||||
const optionValue = option.dataset.value;
|
||||
|
||||
if (optionValue === correctAnswer) {
|
||||
option.classList.add('correct');
|
||||
} else if (option.classList.contains('selected')) {
|
||||
option.classList.add('incorrect');
|
||||
}
|
||||
|
||||
// 禁用点击
|
||||
option.style.pointerEvents = 'none';
|
||||
});
|
||||
}
|
||||
|
||||
// 标记正确答案
|
||||
markCorrectAnswer() {
|
||||
const options = document.querySelectorAll('.option');
|
||||
const correctAnswer = this.currentQuestion.answer;
|
||||
|
||||
options.forEach(option => {
|
||||
const optionValue = option.dataset.value;
|
||||
|
||||
if (optionValue === correctAnswer) {
|
||||
option.classList.add('correct');
|
||||
}
|
||||
|
||||
// 禁用点击
|
||||
option.style.pointerEvents = 'none';
|
||||
});
|
||||
}
|
||||
|
||||
// 格式化解析内容
|
||||
formatExplanation(explanation) {
|
||||
// 转义HTML
|
||||
let formatted = this.escapeHtml(explanation);
|
||||
|
||||
// 处理代码块
|
||||
formatted = formatted.replace(/```js\n([\s\S]*?)\n```/g, '<pre><code>$1</code></pre>');
|
||||
formatted = formatted.replace(/```javascript\n([\s\S]*?)\n```/g, '<pre><code>$1</code></pre>');
|
||||
formatted = formatted.replace(/```([\s\S]*?)```/g, '<pre><code>$1</code></pre>');
|
||||
|
||||
// 处理行内代码
|
||||
formatted = formatted.replace(/`([^`]+)`/g, '<code style="background: #f0f0f0; padding: 2px 4px; border-radius: 3px; font-family: monospace;">$1</code>');
|
||||
|
||||
// 处理换行
|
||||
formatted = formatted.replace(/\n\n/g, '</p><p>');
|
||||
formatted = formatted.replace(/\n/g, '<br>');
|
||||
|
||||
// 包装段落
|
||||
if (!formatted.includes('<p>')) {
|
||||
formatted = '<p>' + formatted + '</p>';
|
||||
}
|
||||
|
||||
return formatted;
|
||||
}
|
||||
|
||||
// HTML转义
|
||||
escapeHtml(text) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
// 导出为Markdown
|
||||
exportToMarkdown() {
|
||||
if (!this.currentQuestion) {
|
||||
alert('请先加载题目后再导出!');
|
||||
return;
|
||||
}
|
||||
|
||||
const question = this.currentQuestion;
|
||||
const timestamp = new Date().toLocaleString('zh-CN');
|
||||
|
||||
// 构建Markdown内容
|
||||
let markdown = `# JavaScript趣味题 #${question.id}\n\n`;
|
||||
markdown += `> 导出时间: ${timestamp}\n\n`;
|
||||
|
||||
// 题目部分
|
||||
markdown += `## 题目\n\n`;
|
||||
markdown += `${question.question}\n\n`;
|
||||
|
||||
// 代码部分
|
||||
markdown += `## 代码\n\n`;
|
||||
markdown += `\`\`\`javascript\n${question.code}\n\`\`\`\n\n`;
|
||||
|
||||
// 选项部分
|
||||
markdown += `## 选项\n\n`;
|
||||
question.options.forEach((option, index) => {
|
||||
const letter = String.fromCharCode(65 + index); // A, B, C, D
|
||||
const isCorrect = letter === question.answer;
|
||||
markdown += `${letter}. ${option}${isCorrect ? ' ✅' : ''}\n`;
|
||||
});
|
||||
markdown += `\n`;
|
||||
|
||||
// 答案部分
|
||||
markdown += `## 正确答案\n\n`;
|
||||
markdown += `**${question.answer}**\n\n`;
|
||||
|
||||
// 解析部分
|
||||
markdown += `## 答案解析\n\n`;
|
||||
// 清理解析内容中的HTML标签,转换为Markdown格式
|
||||
let explanation = question.explanation;
|
||||
explanation = explanation.replace(/<br\s*\/?>/gi, '\n');
|
||||
explanation = explanation.replace(/<p>/gi, '\n');
|
||||
explanation = explanation.replace(/<\/p>/gi, '\n');
|
||||
explanation = explanation.replace(/<code[^>]*>/gi, '`');
|
||||
explanation = explanation.replace(/<\/code>/gi, '`');
|
||||
explanation = explanation.replace(/<pre><code>/gi, '\n```javascript\n');
|
||||
explanation = explanation.replace(/<\/code><\/pre>/gi, '\n```\n');
|
||||
explanation = explanation.replace(/<[^>]*>/g, ''); // 移除其他HTML标签
|
||||
explanation = explanation.replace(/\n\s*\n/g, '\n\n'); // 清理多余空行
|
||||
markdown += explanation.trim() + '\n\n';
|
||||
|
||||
// 添加页脚
|
||||
markdown += `---\n\n`;
|
||||
markdown += `*本题目来源于JavaScript趣味题集合*\n`;
|
||||
markdown += `*导出工具: JavaScript趣味题网页版*\n`;
|
||||
|
||||
// 创建下载
|
||||
this.downloadMarkdown(markdown, `JavaScript趣味题_${question.id}_${new Date().getTime()}.md`);
|
||||
}
|
||||
|
||||
// 下载Markdown文件
|
||||
downloadMarkdown(content, filename) {
|
||||
const blob = new Blob([content], { type: 'text/markdown;charset=utf-8' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = filename;
|
||||
link.style.display = 'none';
|
||||
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
// 清理URL对象
|
||||
setTimeout(() => {
|
||||
URL.revokeObjectURL(url);
|
||||
}, 100);
|
||||
|
||||
// 显示成功提示
|
||||
this.showExportSuccess(filename);
|
||||
}
|
||||
|
||||
// 显示导出成功提示
|
||||
showExportSuccess(filename) {
|
||||
// 创建临时提示元素
|
||||
const toast = document.createElement('div');
|
||||
toast.style.cssText = `
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background: linear-gradient(135deg, #4caf50, #45a049);
|
||||
color: white;
|
||||
padding: 15px 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(76, 175, 80, 0.3);
|
||||
z-index: 10000;
|
||||
font-size: 14px;
|
||||
max-width: 300px;
|
||||
word-wrap: break-word;
|
||||
animation: slideInRight 0.3s ease-out;
|
||||
`;
|
||||
|
||||
toast.innerHTML = `
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="20 6 9 17 4 12"></polyline>
|
||||
</svg>
|
||||
<div>
|
||||
<div style="font-weight: 600;">导出成功!</div>
|
||||
<div style="font-size: 12px; opacity: 0.9; margin-top: 2px;">${filename}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 添加动画样式
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@keyframes slideOutRight {
|
||||
from {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
document.body.appendChild(toast);
|
||||
|
||||
// 3秒后自动消失
|
||||
setTimeout(() => {
|
||||
toast.style.animation = 'slideOutRight 0.3s ease-in';
|
||||
setTimeout(() => {
|
||||
if (toast.parentNode) {
|
||||
document.body.removeChild(toast);
|
||||
}
|
||||
if (style.parentNode) {
|
||||
document.head.removeChild(style);
|
||||
}
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载完成后初始化应用
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
new JSQuizApp();
|
||||
});
|
||||
|
||||
// 添加键盘快捷键支持
|
||||
document.addEventListener('keydown', (e) => {
|
||||
// 按R键刷新题目
|
||||
if (e.key.toLowerCase() === 'r' && !e.ctrlKey && !e.metaKey) {
|
||||
const refreshBtn = document.getElementById('refreshBtn');
|
||||
if (refreshBtn && !document.querySelector('.loading').style.display !== 'none') {
|
||||
refreshBtn.click();
|
||||
}
|
||||
}
|
||||
|
||||
// 按数字键1-4选择选项
|
||||
if (['1', '2', '3', '4'].includes(e.key)) {
|
||||
const options = document.querySelectorAll('.option');
|
||||
const index = parseInt(e.key) - 1;
|
||||
if (options[index] && !options[index].style.pointerEvents) {
|
||||
options[index].click();
|
||||
}
|
||||
}
|
||||
|
||||
// 按Enter键提交答案
|
||||
if (e.key === 'Enter') {
|
||||
const submitBtn = document.getElementById('submitBtn');
|
||||
if (submitBtn && !submitBtn.disabled) {
|
||||
submitBtn.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 添加触摸设备支持
|
||||
if ('ontouchstart' in window) {
|
||||
document.addEventListener('touchstart', () => {}, { passive: true });
|
||||
}
|
||||
|
||||
// 添加网络状态监听
|
||||
if ('navigator' in window && 'onLine' in navigator) {
|
||||
window.addEventListener('online', () => {
|
||||
console.log('网络连接已恢复');
|
||||
});
|
||||
|
||||
window.addEventListener('offline', () => {
|
||||
console.log('网络连接已断开');
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
[
|
||||
"https://60s.api.shumengya.top"
|
||||
]
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841",
|
||||
"data": {
|
||||
"id": 11,
|
||||
"question": "输出是什么?",
|
||||
"code": "function Person(firstName, lastName) {\n this.firstName = firstName;\n this.lastName = lastName;\n}\n\nconst member = new Person(\"Lydia\", \"Hallie\");\nPerson.getFullName = function () {\n return `${this.firstName} ${this.lastName}`;\n}\n\nconsole.log(member.getFullName());",
|
||||
"options": [
|
||||
"A: `TypeError`",
|
||||
"B: `SyntaxError`",
|
||||
"C: `Lydia Hallie`",
|
||||
"D: `undefined` `undefined`"
|
||||
],
|
||||
"answer": "A",
|
||||
"explanation": "你不能像常规对象那样,给构造函数添加属性。如果你想一次性给所有实例添加特性,你应该使用原型。因此本例中,使用如下方式:\n\n```js\nPerson.prototype.getFullName = function () {\n return `${this.firstName} ${this.lastName}`;\n}\n```\n\n这才会使 `member.getFullName()` 起作用。为什么这么做有益的?假设我们将这个方法添加到构造函数本身里。也许不是每个 `Person` 实例都需要这个方法。这将浪费大量内存空间,因为它们仍然具有该属性,这将占用每个实例的内存空间。相反,如果我们只将它添加到原型中,那么它只存在于内存中的一个位置,但是所有实例都可以访问它!"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/* 背景样式文件 */
|
||||
body {
|
||||
background: linear-gradient(135deg, #a8e6cf 0%, #dcedc1 25%, #ffd3a5 50%, #a8e6cf 75%, #88d8a3 100%);
|
||||
background-size: 400% 400%;
|
||||
animation: gradientShift 15s ease infinite;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 背景动画 */
|
||||
@keyframes gradientShift {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
/* 背景装饰元素 */
|
||||
body::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image:
|
||||
radial-gradient(circle at 20% 80%, rgba(39, 174, 96, 0.1) 0%, transparent 50%),
|
||||
radial-gradient(circle at 80% 20%, rgba(46, 204, 113, 0.1) 0%, transparent 50%),
|
||||
radial-gradient(circle at 40% 40%, rgba(26, 188, 156, 0.05) 0%, transparent 50%);
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
/* 浮动装饰圆点 */
|
||||
body::after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image:
|
||||
radial-gradient(2px 2px at 20px 30px, rgba(39, 174, 96, 0.3), transparent),
|
||||
radial-gradient(2px 2px at 40px 70px, rgba(46, 204, 113, 0.2), transparent),
|
||||
radial-gradient(1px 1px at 90px 40px, rgba(26, 188, 156, 0.3), transparent),
|
||||
radial-gradient(1px 1px at 130px 80px, rgba(39, 174, 96, 0.2), transparent),
|
||||
radial-gradient(2px 2px at 160px 30px, rgba(46, 204, 113, 0.3), transparent);
|
||||
background-repeat: repeat;
|
||||
background-size: 200px 100px;
|
||||
animation: floatDots 20s linear infinite;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
@keyframes floatDots {
|
||||
0% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-100px);
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式背景调整 */
|
||||
@media (max-width: 768px) {
|
||||
body::after {
|
||||
background-size: 150px 75px;
|
||||
animation-duration: 25s;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
body::after {
|
||||
background-size: 100px 50px;
|
||||
animation-duration: 30s;
|
||||
}
|
||||
}
|
||||
339
InfoGenie-frontend/public/60sapi/娱乐消遣/随机KFC文案/css/style.css
Normal file
339
InfoGenie-frontend/public/60sapi/娱乐消遣/随机KFC文案/css/style.css
Normal file
@@ -0,0 +1,339 @@
|
||||
/* 基础样式重置 */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Microsoft YaHei', 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #2c3e50;
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* 容器布局 */
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* 头部样式 */
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
padding: 30px 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 700;
|
||||
color: #27ae60;
|
||||
margin-bottom: 10px;
|
||||
text-shadow: 0 2px 4px rgba(39, 174, 96, 0.2);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1.1rem;
|
||||
color: #7f8c8d;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* 主要内容区域 */
|
||||
.main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.content-card {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 20px;
|
||||
padding: 40px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(39, 174, 96, 0.1);
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.content-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
/* KFC文案内容 */
|
||||
.kfc-content {
|
||||
min-height: 200px;
|
||||
padding: 30px;
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||||
border-radius: 15px;
|
||||
border-left: 5px solid #27ae60;
|
||||
margin-bottom: 30px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.kfc-content::before {
|
||||
content: '"';
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 15px;
|
||||
font-size: 3rem;
|
||||
color: #27ae60;
|
||||
opacity: 0.3;
|
||||
font-family: serif;
|
||||
}
|
||||
|
||||
.kfc-content p {
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.8;
|
||||
color: #2c3e50;
|
||||
margin-left: 20px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
text-align: center;
|
||||
color: #7f8c8d;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* 按钮组 */
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.generate-btn, .copy-btn {
|
||||
padding: 15px 30px;
|
||||
border: none;
|
||||
border-radius: 50px;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.generate-btn {
|
||||
background: linear-gradient(135deg, #27ae60 0%, #2ecc71 100%);
|
||||
color: white;
|
||||
box-shadow: 0 4px 15px rgba(39, 174, 96, 0.3);
|
||||
}
|
||||
|
||||
.generate-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(39, 174, 96, 0.4);
|
||||
}
|
||||
|
||||
.generate-btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.generate-btn:disabled {
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
background: linear-gradient(135deg, #3498db 0%, #5dade2 100%);
|
||||
color: white;
|
||||
box-shadow: 0 4px 15px rgba(52, 152, 219, 0.3);
|
||||
}
|
||||
|
||||
.copy-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(52, 152, 219, 0.4);
|
||||
}
|
||||
|
||||
/* 编号信息 */
|
||||
.index-info {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
background: rgba(39, 174, 96, 0.1);
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(39, 174, 96, 0.2);
|
||||
}
|
||||
|
||||
.index-text {
|
||||
color: #27ae60;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
#indexNumber {
|
||||
color: #2c3e50;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* 底部 */
|
||||
.footer {
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
color: #7f8c8d;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
/* 提示框 */
|
||||
.toast {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background: #27ae60;
|
||||
color: white;
|
||||
padding: 15px 25px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
||||
transform: translateX(400px);
|
||||
transition: transform 0.3s ease;
|
||||
z-index: 1000;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.toast.show {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
/* 平板端适配 (768px - 1024px) */
|
||||
@media (max-width: 1024px) and (min-width: 768px) {
|
||||
.container {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 2.2rem;
|
||||
}
|
||||
|
||||
.content-card {
|
||||
padding: 35px;
|
||||
max-width: 550px;
|
||||
}
|
||||
|
||||
.kfc-content {
|
||||
padding: 25px;
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
flex-direction: row;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.generate-btn, .copy-btn {
|
||||
padding: 12px 25px;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 手机端适配 (最大768px) */
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 30px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 1.8rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.content-card {
|
||||
padding: 25px;
|
||||
margin: 0 5px;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.kfc-content {
|
||||
padding: 20px;
|
||||
min-height: 150px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.kfc-content::before {
|
||||
font-size: 2.5rem;
|
||||
top: 5px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.kfc-content p {
|
||||
font-size: 1rem;
|
||||
line-height: 1.7;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.generate-btn, .copy-btn {
|
||||
padding: 12px 20px;
|
||||
font-size: 0.9rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.footer {
|
||||
font-size: 0.8rem;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.toast {
|
||||
right: 10px;
|
||||
left: 10px;
|
||||
transform: translateY(-100px);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.toast.show {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 小屏手机适配 (最大480px) */
|
||||
@media (max-width: 480px) {
|
||||
.title {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
.content-card {
|
||||
padding: 20px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.kfc-content {
|
||||
padding: 15px;
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.kfc-content p {
|
||||
font-size: 0.95rem;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.generate-btn, .copy-btn {
|
||||
padding: 10px 15px;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
}
|
||||
46
InfoGenie-frontend/public/60sapi/娱乐消遣/随机KFC文案/index.html
Normal file
46
InfoGenie-frontend/public/60sapi/娱乐消遣/随机KFC文案/index.html
Normal file
@@ -0,0 +1,46 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>随机KFC文案生成器</title>
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<link rel="stylesheet" href="css/background.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header class="header">
|
||||
<h1 class="title">🍗 随机KFC文案生成器</h1>
|
||||
<p class="subtitle">疯狂星期四,文案来一套!</p>
|
||||
</header>
|
||||
|
||||
<main class="main">
|
||||
<div class="content-card">
|
||||
<div class="kfc-content" id="kfcContent">
|
||||
<p class="loading-text">点击按钮获取随机KFC文案...</p>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button class="generate-btn" id="generateBtn">
|
||||
<span class="btn-text">生成文案</span>
|
||||
<span class="btn-loading" style="display: none;">生成中...</span>
|
||||
</button>
|
||||
<button class="copy-btn" id="copyBtn" style="display: none;">复制文案</button>
|
||||
</div>
|
||||
|
||||
<div class="index-info" id="indexInfo" style="display: none;">
|
||||
<span class="index-text">文案编号: <span id="indexNumber"></span></span>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
<p>© 2024 KFC文案生成器 | 让每个星期四都疯狂起来</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
240
InfoGenie-frontend/public/60sapi/娱乐消遣/随机KFC文案/js/main.js
Normal file
240
InfoGenie-frontend/public/60sapi/娱乐消遣/随机KFC文案/js/main.js
Normal file
@@ -0,0 +1,240 @@
|
||||
// KFC文案生成器主要功能
|
||||
class KFCGenerator {
|
||||
constructor() {
|
||||
this.apiEndpoints = [];
|
||||
this.currentApiIndex = 0;
|
||||
this.isLoading = false;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
// 初始化
|
||||
async init() {
|
||||
await this.loadApiEndpoints();
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
// 加载API接口列表
|
||||
async loadApiEndpoints() {
|
||||
try {
|
||||
// 直接硬编码API端点,避免CORS问题
|
||||
this.apiEndpoints = ["https://60s.api.shumengya.top"];
|
||||
} catch (error) {
|
||||
console.error('加载API接口列表失败:', error);
|
||||
this.showToast('加载接口配置失败', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定事件
|
||||
bindEvents() {
|
||||
const generateBtn = document.getElementById('generateBtn');
|
||||
const copyBtn = document.getElementById('copyBtn');
|
||||
|
||||
generateBtn.addEventListener('click', () => this.generateKFC());
|
||||
copyBtn.addEventListener('click', () => this.copyContent());
|
||||
}
|
||||
|
||||
// 生成KFC文案
|
||||
async generateKFC() {
|
||||
if (this.isLoading) return;
|
||||
|
||||
this.setLoadingState(true);
|
||||
|
||||
let success = false;
|
||||
let attempts = 0;
|
||||
const maxAttempts = this.apiEndpoints.length;
|
||||
|
||||
while (!success && attempts < maxAttempts) {
|
||||
try {
|
||||
const apiUrl = this.apiEndpoints[this.currentApiIndex];
|
||||
const data = await this.fetchKFCData(apiUrl);
|
||||
|
||||
if (data && data.code === 200 && data.data && data.data.kfc) {
|
||||
this.displayKFC(data.data);
|
||||
success = true;
|
||||
} else {
|
||||
throw new Error('API返回数据格式错误');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`API ${this.currentApiIndex + 1} 请求失败:`, error);
|
||||
this.currentApiIndex = (this.currentApiIndex + 1) % this.apiEndpoints.length;
|
||||
attempts++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
this.showError('所有API接口都无法访问,请稍后重试');
|
||||
}
|
||||
|
||||
this.setLoadingState(false);
|
||||
}
|
||||
|
||||
// 请求KFC数据
|
||||
async fetchKFCData(apiUrl) {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时
|
||||
|
||||
try {
|
||||
const response = await fetch(`${apiUrl}/v2/kfc`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
signal: controller.signal
|
||||
});
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
clearTimeout(timeoutId);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 显示KFC文案
|
||||
displayKFC(data) {
|
||||
const contentElement = document.getElementById('kfcContent');
|
||||
const indexElement = document.getElementById('indexNumber');
|
||||
const indexInfo = document.getElementById('indexInfo');
|
||||
const copyBtn = document.getElementById('copyBtn');
|
||||
|
||||
// 显示文案内容
|
||||
contentElement.innerHTML = `<p>${this.escapeHtml(data.kfc)}</p>`;
|
||||
|
||||
// 显示编号信息
|
||||
if (data.index) {
|
||||
indexElement.textContent = data.index;
|
||||
indexInfo.style.display = 'block';
|
||||
} else {
|
||||
indexInfo.style.display = 'none';
|
||||
}
|
||||
|
||||
// 显示复制按钮
|
||||
copyBtn.style.display = 'inline-block';
|
||||
|
||||
// 添加显示动画
|
||||
contentElement.style.opacity = '0';
|
||||
contentElement.style.transform = 'translateY(20px)';
|
||||
|
||||
setTimeout(() => {
|
||||
contentElement.style.transition = 'all 0.5s ease';
|
||||
contentElement.style.opacity = '1';
|
||||
contentElement.style.transform = 'translateY(0)';
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// 显示错误信息
|
||||
showError(message) {
|
||||
const contentElement = document.getElementById('kfcContent');
|
||||
contentElement.innerHTML = `<p class="loading-text" style="color: #e74c3c;">${this.escapeHtml(message)}</p>`;
|
||||
|
||||
const copyBtn = document.getElementById('copyBtn');
|
||||
const indexInfo = document.getElementById('indexInfo');
|
||||
copyBtn.style.display = 'none';
|
||||
indexInfo.style.display = 'none';
|
||||
}
|
||||
|
||||
// 复制文案内容
|
||||
async copyContent() {
|
||||
const contentElement = document.getElementById('kfcContent');
|
||||
const textContent = contentElement.querySelector('p')?.textContent;
|
||||
|
||||
if (!textContent || textContent.includes('点击按钮获取') || textContent.includes('失败')) {
|
||||
this.showToast('没有可复制的内容', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
await navigator.clipboard.writeText(textContent);
|
||||
} else {
|
||||
// 降级方案
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.value = textContent;
|
||||
textArea.style.position = 'fixed';
|
||||
textArea.style.left = '-999999px';
|
||||
textArea.style.top = '-999999px';
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
document.execCommand('copy');
|
||||
textArea.remove();
|
||||
}
|
||||
|
||||
this.showToast('文案已复制到剪贴板', 'success');
|
||||
} catch (error) {
|
||||
console.error('复制失败:', error);
|
||||
this.showToast('复制失败,请手动选择复制', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 设置加载状态
|
||||
setLoadingState(loading) {
|
||||
this.isLoading = loading;
|
||||
const generateBtn = document.getElementById('generateBtn');
|
||||
const btnText = generateBtn.querySelector('.btn-text');
|
||||
const btnLoading = generateBtn.querySelector('.btn-loading');
|
||||
|
||||
if (loading) {
|
||||
generateBtn.disabled = true;
|
||||
btnText.style.display = 'none';
|
||||
btnLoading.style.display = 'inline';
|
||||
} else {
|
||||
generateBtn.disabled = false;
|
||||
btnText.style.display = 'inline';
|
||||
btnLoading.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// 显示提示消息
|
||||
showToast(message, type = 'success') {
|
||||
const toast = document.getElementById('toast');
|
||||
toast.textContent = message;
|
||||
toast.className = `toast ${type}`;
|
||||
toast.classList.add('show');
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show');
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// HTML转义
|
||||
escapeHtml(text) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载完成后初始化
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const generator = new KFCGenerator();
|
||||
// 页面加载完成后自动生成一条文案
|
||||
setTimeout(() => {
|
||||
generator.generateKFC();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
// 添加键盘快捷键支持
|
||||
document.addEventListener('keydown', (event) => {
|
||||
// 按空格键生成文案
|
||||
if (event.code === 'Space' && event.target.tagName !== 'INPUT' && event.target.tagName !== 'TEXTAREA') {
|
||||
event.preventDefault();
|
||||
document.getElementById('generateBtn').click();
|
||||
}
|
||||
|
||||
// Ctrl+C 复制文案
|
||||
if (event.ctrlKey && event.key === 'c' && event.target.tagName !== 'INPUT' && event.target.tagName !== 'TEXTAREA') {
|
||||
const copyBtn = document.getElementById('copyBtn');
|
||||
if (copyBtn.style.display !== 'none') {
|
||||
event.preventDefault();
|
||||
copyBtn.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
3
InfoGenie-frontend/public/60sapi/娱乐消遣/随机KFC文案/接口集合.json
Normal file
3
InfoGenie-frontend/public/60sapi/娱乐消遣/随机KFC文案/接口集合.json
Normal file
@@ -0,0 +1,3 @@
|
||||
[
|
||||
"https://60s.api.shumengya.top"
|
||||
]
|
||||
8
InfoGenie-frontend/public/60sapi/娱乐消遣/随机KFC文案/返回接口.json
Normal file
8
InfoGenie-frontend/public/60sapi/娱乐消遣/随机KFC文案/返回接口.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841",
|
||||
"data": {
|
||||
"index": 78,
|
||||
"kfc": "我叫夯大力 立冬给我准备了糖炒栗子了没有 没准备的自动绝交 再 v 我 50 吃疯狂星期四 然后再给我点杯奶茶 再给我两万块钱 懂吗你们"
|
||||
}
|
||||
}
|
||||
167
InfoGenie-frontend/public/60sapi/娱乐消遣/随机一言/css/background.css
Normal file
167
InfoGenie-frontend/public/60sapi/娱乐消遣/随机一言/css/background.css
Normal file
@@ -0,0 +1,167 @@
|
||||
/* 背景样式文件 - 金色光辉主题 */
|
||||
|
||||
/* 主背景 */
|
||||
body {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
#fff8dc 0%,
|
||||
#ffeaa7 25%,
|
||||
#fdcb6e 50%,
|
||||
#e17055 75%,
|
||||
#d63031 100%
|
||||
);
|
||||
background-size: 400% 400%;
|
||||
animation: gradientShift 15s ease infinite;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 背景装饰层 */
|
||||
body::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background:
|
||||
radial-gradient(circle at 20% 80%, rgba(255, 215, 0, 0.1) 0%, transparent 50%),
|
||||
radial-gradient(circle at 80% 20%, rgba(255, 223, 0, 0.1) 0%, transparent 50%),
|
||||
radial-gradient(circle at 40% 40%, rgba(212, 175, 55, 0.05) 0%, transparent 50%);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* 动态光点效果 */
|
||||
body::after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image:
|
||||
radial-gradient(2px 2px at 20px 30px, rgba(255, 215, 0, 0.3), transparent),
|
||||
radial-gradient(2px 2px at 40px 70px, rgba(255, 223, 0, 0.2), transparent),
|
||||
radial-gradient(1px 1px at 90px 40px, rgba(212, 175, 55, 0.4), transparent),
|
||||
radial-gradient(1px 1px at 130px 80px, rgba(255, 215, 0, 0.2), transparent),
|
||||
radial-gradient(2px 2px at 160px 30px, rgba(255, 223, 0, 0.3), transparent);
|
||||
background-repeat: repeat;
|
||||
background-size: 200px 100px;
|
||||
animation: sparkle 20s linear infinite;
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* 背景动画 */
|
||||
@keyframes gradientShift {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sparkle {
|
||||
0% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-100vh);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式背景调整 */
|
||||
|
||||
/* 平板端背景 */
|
||||
@media (min-width: 768px) and (max-width: 1024px) {
|
||||
body::after {
|
||||
background-size: 250px 120px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 电脑端背景 */
|
||||
@media (min-width: 1024px) {
|
||||
body {
|
||||
background-size: 300% 300%;
|
||||
}
|
||||
|
||||
body::after {
|
||||
background-size: 300px 150px;
|
||||
animation-duration: 25s;
|
||||
}
|
||||
}
|
||||
|
||||
/* 手机端背景优化 */
|
||||
@media (max-width: 767px) {
|
||||
body {
|
||||
background-size: 200% 200%;
|
||||
animation-duration: 10s;
|
||||
}
|
||||
|
||||
body::before {
|
||||
background:
|
||||
radial-gradient(circle at 30% 70%, rgba(255, 215, 0, 0.08) 0%, transparent 40%),
|
||||
radial-gradient(circle at 70% 30%, rgba(255, 223, 0, 0.08) 0%, transparent 40%);
|
||||
}
|
||||
|
||||
body::after {
|
||||
background-size: 150px 80px;
|
||||
animation-duration: 15s;
|
||||
}
|
||||
}
|
||||
|
||||
/* 超小屏幕背景 */
|
||||
@media (max-width: 479px) {
|
||||
body {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
#fff8dc 0%,
|
||||
#ffeaa7 50%,
|
||||
#fdcb6e 100%
|
||||
);
|
||||
background-size: 150% 150%;
|
||||
}
|
||||
|
||||
body::after {
|
||||
background-size: 120px 60px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 深色模式支持 */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
#2c1810 0%,
|
||||
#3d2914 25%,
|
||||
#4a3319 50%,
|
||||
#5c3e1f 75%,
|
||||
#6b4423 100%
|
||||
);
|
||||
}
|
||||
|
||||
body::before {
|
||||
background:
|
||||
radial-gradient(circle at 20% 80%, rgba(255, 215, 0, 0.05) 0%, transparent 50%),
|
||||
radial-gradient(circle at 80% 20%, rgba(255, 223, 0, 0.05) 0%, transparent 50%);
|
||||
}
|
||||
}
|
||||
|
||||
/* 减少动画效果(用户偏好) */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
body,
|
||||
body::before,
|
||||
body::after {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
body {
|
||||
background: linear-gradient(135deg, #fff8dc 0%, #ffeaa7 50%, #fdcb6e 100%);
|
||||
}
|
||||
}
|
||||
357
InfoGenie-frontend/public/60sapi/娱乐消遣/随机一言/css/style.css
Normal file
357
InfoGenie-frontend/public/60sapi/娱乐消遣/随机一言/css/style.css
Normal file
@@ -0,0 +1,357 @@
|
||||
/* 基础样式重置 */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Microsoft YaHei', 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #2c1810;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* 容器布局 */
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 头部样式 */
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
color: #d4af37;
|
||||
text-shadow:
|
||||
0 0 10px rgba(212, 175, 55, 0.8),
|
||||
0 0 20px rgba(212, 175, 55, 0.6),
|
||||
0 0 30px rgba(212, 175, 55, 0.4);
|
||||
margin-bottom: 10px;
|
||||
animation: titleGlow 3s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1.2rem;
|
||||
color: #b8860b;
|
||||
opacity: 0.9;
|
||||
text-shadow: 0 0 5px rgba(184, 134, 11, 0.5);
|
||||
}
|
||||
|
||||
/* 主内容区域 */
|
||||
.main-content {
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/* 一言容器 */
|
||||
.quote-container {
|
||||
background: linear-gradient(135deg, rgba(255, 215, 0, 0.1), rgba(255, 223, 0, 0.05));
|
||||
border: 2px solid rgba(212, 175, 55, 0.3);
|
||||
border-radius: 20px;
|
||||
padding: 40px;
|
||||
margin-bottom: 30px;
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow:
|
||||
0 8px 32px rgba(212, 175, 55, 0.2),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.quote-container::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
left: -2px;
|
||||
right: -2px;
|
||||
bottom: -2px;
|
||||
background: linear-gradient(45deg, #ffd700, #ffed4e, #ffd700, #ffed4e);
|
||||
border-radius: 22px;
|
||||
z-index: -1;
|
||||
animation: borderGlow 4s linear infinite;
|
||||
}
|
||||
|
||||
/* 加载状态 */
|
||||
.loading {
|
||||
display: none;
|
||||
text-align: center;
|
||||
color: #d4af37;
|
||||
}
|
||||
|
||||
.loading.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 4px solid rgba(212, 175, 55, 0.3);
|
||||
border-top: 4px solid #d4af37;
|
||||
border-radius: 50%;
|
||||
margin: 0 auto 15px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
/* 一言显示 */
|
||||
.quote-display {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.quote-display.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.quote-text {
|
||||
font-size: 1.8rem;
|
||||
line-height: 1.8;
|
||||
color: #2c1810;
|
||||
margin-bottom: 20px;
|
||||
text-shadow: 0 1px 2px rgba(212, 175, 55, 0.1);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.quote-index {
|
||||
font-size: 0.9rem;
|
||||
color: #b8860b;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* 错误信息 */
|
||||
.error-message {
|
||||
display: none;
|
||||
text-align: center;
|
||||
color: #cd853f;
|
||||
}
|
||||
|
||||
.error-message.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.error-icon {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* 控制按钮 */
|
||||
.controls {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
background: linear-gradient(135deg, #ffd700, #ffed4e);
|
||||
border: none;
|
||||
border-radius: 50px;
|
||||
padding: 15px 30px;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: #2c1810;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow:
|
||||
0 4px 15px rgba(212, 175, 55, 0.3),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.3);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.refresh-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow:
|
||||
0 6px 20px rgba(212, 175, 55, 0.4),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.refresh-btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.refresh-btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
font-size: 1.2rem;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.refresh-btn:hover .btn-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* 底部 */
|
||||
.footer {
|
||||
margin-top: 40px;
|
||||
text-align: center;
|
||||
color: #b8860b;
|
||||
opacity: 0.8;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* 动画效果 */
|
||||
@keyframes titleGlow {
|
||||
0% {
|
||||
text-shadow:
|
||||
0 0 10px rgba(212, 175, 55, 0.8),
|
||||
0 0 20px rgba(212, 175, 55, 0.6),
|
||||
0 0 30px rgba(212, 175, 55, 0.4);
|
||||
}
|
||||
100% {
|
||||
text-shadow:
|
||||
0 0 15px rgba(212, 175, 55, 1),
|
||||
0 0 25px rgba(212, 175, 55, 0.8),
|
||||
0 0 35px rgba(212, 175, 55, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes borderGlow {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* 平板端适配 (768px - 1024px) */
|
||||
@media (min-width: 768px) and (max-width: 1024px) {
|
||||
.container {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 3.5rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.quote-container {
|
||||
padding: 50px;
|
||||
}
|
||||
|
||||
.quote-text {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 电脑端适配 (1024px+) */
|
||||
@media (min-width: 1024px) {
|
||||
.container {
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 4rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.quote-container {
|
||||
padding: 60px;
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
.quote-text {
|
||||
font-size: 2.2rem;
|
||||
line-height: 1.9;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
padding: 18px 36px;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 手机端适配 (小于768px) */
|
||||
@media (max-width: 767px) {
|
||||
.container {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.quote-container {
|
||||
padding: 25px;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.quote-text {
|
||||
font-size: 1.4rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
padding: 12px 24px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 30px;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 超小屏幕适配 (小于480px) */
|
||||
@media (max-width: 479px) {
|
||||
.title {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.quote-container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.quote-text {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
padding: 10px 20px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
52
InfoGenie-frontend/public/60sapi/娱乐消遣/随机一言/index.html
Normal file
52
InfoGenie-frontend/public/60sapi/娱乐消遣/随机一言/index.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>随机一言 - 金色光辉</title>
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<link rel="stylesheet" href="css/background.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header class="header">
|
||||
<h1 class="title">随机一言</h1>
|
||||
<p class="subtitle">每一句话都是心灵的光芒</p>
|
||||
</header>
|
||||
|
||||
<main class="main-content">
|
||||
<div class="quote-container">
|
||||
<div class="loading" id="loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>正在获取一言...</p>
|
||||
</div>
|
||||
|
||||
<div class="quote-display" id="quoteDisplay">
|
||||
<div class="quote-text" id="quoteText">
|
||||
点击下方按钮获取一言
|
||||
</div>
|
||||
<div class="quote-index" id="quoteIndex"></div>
|
||||
</div>
|
||||
|
||||
<div class="error-message" id="errorMessage">
|
||||
<div class="error-icon">⚠️</div>
|
||||
<div class="error-text" id="errorText"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<button class="refresh-btn" id="refreshBtn">
|
||||
<span class="btn-icon">🔄</span>
|
||||
<span class="btn-text">获取新一言</span>
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
<p>愿每一句话都能温暖你的心</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<script src="js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
222
InfoGenie-frontend/public/60sapi/娱乐消遣/随机一言/js/script.js
Normal file
222
InfoGenie-frontend/public/60sapi/娱乐消遣/随机一言/js/script.js
Normal file
@@ -0,0 +1,222 @@
|
||||
// 随机一言 JavaScript 功能实现
|
||||
|
||||
class HitokotoApp {
|
||||
constructor() {
|
||||
// API接口列表
|
||||
this.apiEndpoints = [
|
||||
"https://60s.api.shumengya.top"
|
||||
];
|
||||
|
||||
this.currentEndpointIndex = 0;
|
||||
this.isLoading = false;
|
||||
|
||||
// DOM 元素
|
||||
this.elements = {
|
||||
loading: document.getElementById('loading'),
|
||||
quoteDisplay: document.getElementById('quoteDisplay'),
|
||||
quoteText: document.getElementById('quoteText'),
|
||||
quoteIndex: document.getElementById('quoteIndex'),
|
||||
errorMessage: document.getElementById('errorMessage'),
|
||||
errorText: document.getElementById('errorText'),
|
||||
refreshBtn: document.getElementById('refreshBtn')
|
||||
};
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
// 初始化应用
|
||||
init() {
|
||||
this.bindEvents();
|
||||
this.hideAllStates();
|
||||
this.showQuoteDisplay();
|
||||
}
|
||||
|
||||
// 绑定事件
|
||||
bindEvents() {
|
||||
this.elements.refreshBtn.addEventListener('click', () => {
|
||||
this.fetchHitokoto();
|
||||
});
|
||||
|
||||
// 键盘快捷键支持
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.code === 'Space' && !this.isLoading) {
|
||||
e.preventDefault();
|
||||
this.fetchHitokoto();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 隐藏所有状态
|
||||
hideAllStates() {
|
||||
this.elements.loading.classList.remove('show');
|
||||
this.elements.quoteDisplay.classList.remove('hide');
|
||||
this.elements.errorMessage.classList.remove('show');
|
||||
}
|
||||
|
||||
// 显示加载状态
|
||||
showLoading() {
|
||||
this.hideAllStates();
|
||||
this.elements.loading.classList.add('show');
|
||||
this.elements.quoteDisplay.classList.add('hide');
|
||||
this.elements.refreshBtn.disabled = true;
|
||||
this.isLoading = true;
|
||||
}
|
||||
|
||||
// 显示一言内容
|
||||
showQuoteDisplay() {
|
||||
this.hideAllStates();
|
||||
this.elements.quoteDisplay.classList.remove('hide');
|
||||
this.elements.refreshBtn.disabled = false;
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
// 显示错误信息
|
||||
showError(message) {
|
||||
this.hideAllStates();
|
||||
this.elements.errorMessage.classList.add('show');
|
||||
this.elements.errorText.textContent = message;
|
||||
this.elements.refreshBtn.disabled = false;
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
// 获取一言数据
|
||||
async fetchHitokoto() {
|
||||
if (this.isLoading) return;
|
||||
|
||||
this.showLoading();
|
||||
|
||||
// 尝试所有API接口
|
||||
for (let i = 0; i < this.apiEndpoints.length; i++) {
|
||||
const endpointIndex = (this.currentEndpointIndex + i) % this.apiEndpoints.length;
|
||||
const endpoint = this.apiEndpoints[endpointIndex];
|
||||
|
||||
try {
|
||||
const result = await this.tryFetchFromEndpoint(endpoint);
|
||||
if (result.success) {
|
||||
this.currentEndpointIndex = endpointIndex;
|
||||
this.displayHitokoto(result.data);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`接口 ${endpoint} 请求失败:`, error.message);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 所有接口都失败
|
||||
this.showError('所有接口都无法访问,请检查网络连接或稍后重试');
|
||||
}
|
||||
|
||||
// 尝试从指定接口获取数据
|
||||
async tryFetchFromEndpoint(endpoint) {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时
|
||||
|
||||
try {
|
||||
// 移除URL中的encoding=text参数,确保返回JSON格式
|
||||
const response = await fetch(`${endpoint}/v2/hitokoto`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
signal: controller.signal
|
||||
});
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// 验证返回数据格式
|
||||
if (data.code === 200 && data.data && data.data.hitokoto) {
|
||||
return {
|
||||
success: true,
|
||||
data: data.data
|
||||
};
|
||||
} else {
|
||||
throw new Error('返回数据格式不正确');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (error.name === 'AbortError') {
|
||||
throw new Error('请求超时');
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 显示一言内容
|
||||
displayHitokoto(data) {
|
||||
// 更新一言文本
|
||||
this.elements.quoteText.textContent = data.hitokoto;
|
||||
|
||||
// 更新序号信息
|
||||
if (data.index) {
|
||||
this.elements.quoteIndex.textContent = `第 ${data.index} 条`;
|
||||
} else {
|
||||
this.elements.quoteIndex.textContent = '';
|
||||
}
|
||||
|
||||
// 添加淡入动画效果
|
||||
this.elements.quoteText.style.opacity = '0';
|
||||
this.elements.quoteIndex.style.opacity = '0';
|
||||
|
||||
setTimeout(() => {
|
||||
this.elements.quoteText.style.transition = 'opacity 0.5s ease';
|
||||
this.elements.quoteIndex.style.transition = 'opacity 0.5s ease';
|
||||
this.elements.quoteText.style.opacity = '1';
|
||||
this.elements.quoteIndex.style.opacity = '1';
|
||||
}, 100);
|
||||
|
||||
this.showQuoteDisplay();
|
||||
|
||||
// 控制台输出调试信息
|
||||
console.log('一言获取成功:', {
|
||||
content: data.hitokoto,
|
||||
index: data.index,
|
||||
endpoint: this.apiEndpoints[this.currentEndpointIndex]
|
||||
});
|
||||
}
|
||||
|
||||
// 获取随机接口(用于负载均衡)
|
||||
getRandomEndpoint() {
|
||||
const randomIndex = Math.floor(Math.random() * this.apiEndpoints.length);
|
||||
return this.apiEndpoints[randomIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载完成后初始化应用
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const app = new HitokotoApp();
|
||||
|
||||
// 添加全局错误处理
|
||||
window.addEventListener('error', (event) => {
|
||||
console.error('页面发生错误:', event.error);
|
||||
});
|
||||
|
||||
window.addEventListener('unhandledrejection', (event) => {
|
||||
console.error('未处理的Promise拒绝:', event.reason);
|
||||
});
|
||||
|
||||
// 页面可见性变化时的处理
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (!document.hidden && !app.isLoading) {
|
||||
// 页面重新可见时,可以选择刷新内容
|
||||
console.log('页面重新可见');
|
||||
}
|
||||
});
|
||||
|
||||
console.log('随机一言应用初始化完成');
|
||||
});
|
||||
|
||||
// 导出应用类(如果需要在其他地方使用)
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = HitokotoApp;
|
||||
}
|
||||
3
InfoGenie-frontend/public/60sapi/娱乐消遣/随机一言/接口集合.json
Normal file
3
InfoGenie-frontend/public/60sapi/娱乐消遣/随机一言/接口集合.json
Normal file
@@ -0,0 +1,3 @@
|
||||
[
|
||||
"https://60s.api.shumengya.top"
|
||||
]
|
||||
8
InfoGenie-frontend/public/60sapi/娱乐消遣/随机一言/返回接口.json
Normal file
8
InfoGenie-frontend/public/60sapi/娱乐消遣/随机一言/返回接口.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841",
|
||||
"data": {
|
||||
"index": 2862,
|
||||
"hitokoto": "你带上罪恶之冠,即使背负上所有罪恶和孤独,绝不让你受伤"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>每日笑话</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="card">
|
||||
<p id="joke">加载中...</p>
|
||||
<button id="next">换一个</button>
|
||||
</div>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
107
InfoGenie-frontend/public/60sapi/娱乐消遣/随机冷笑话/css/background.css
Normal file
107
InfoGenie-frontend/public/60sapi/娱乐消遣/随机冷笑话/css/background.css
Normal file
@@ -0,0 +1,107 @@
|
||||
/* background.css - 动态渐变背景 */
|
||||
body {
|
||||
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
|
||||
background-size: 400% 400%;
|
||||
animation: gradient 15s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes gradient {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
:root {
|
||||
--bg-yellow: #FFFDE7; /* 浅黄 */
|
||||
--bg-blue: #E3F2FD; /* 淡蓝 */
|
||||
}
|
||||
|
||||
body {
|
||||
background: linear-gradient(180deg, var(--bg-yellow) 0%, var(--bg-blue) 100%);
|
||||
background-attachment: fixed; /* 固定背景,滚动时不移动 */
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
overflow: hidden;
|
||||
transition: background-color 0.5s ease;
|
||||
}
|
||||
|
||||
/* Light Theme (Default) */
|
||||
[data-theme="light"] {
|
||||
background: linear-gradient(to bottom, #87CEEB, #B0E0E6);
|
||||
}
|
||||
|
||||
/* Dark Theme */
|
||||
[data-theme="dark"] {
|
||||
background: linear-gradient(to bottom, #232526, #414345);
|
||||
}
|
||||
[data-theme="dark"] .snowflake {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* Winter Theme */
|
||||
[data-theme="winter"] {
|
||||
background: linear-gradient(to bottom, #a1c4fd, #c2e9fb);
|
||||
}
|
||||
[data-theme="winter"] .background-bottom {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
background: linear-gradient(to top, white, rgba(255, 255, 255, 0));
|
||||
z-index: -1;
|
||||
border-radius: 50% 50% 0 0 / 20px;
|
||||
box-shadow: 0 -10px 20px rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
|
||||
#snowflake-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.snowflake {
|
||||
position: absolute;
|
||||
top: -10%;
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
user-select: none;
|
||||
animation: fall linear infinite;
|
||||
}
|
||||
|
||||
@keyframes fall {
|
||||
to {
|
||||
transform: translateY(105vh) rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
#frost-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url('https://www.transparenttextures.com/patterns/ice-age.png') repeat;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.5s ease-in-out;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#frost-overlay.is-frosted {
|
||||
opacity: 0.3;
|
||||
}
|
||||
217
InfoGenie-frontend/public/60sapi/娱乐消遣/随机冷笑话/css/style.css
Normal file
217
InfoGenie-frontend/public/60sapi/娱乐消遣/随机冷笑话/css/style.css
Normal file
@@ -0,0 +1,217 @@
|
||||
:root {
|
||||
--primary-color-light: #4A90E2;
|
||||
--text-color-light: #333;
|
||||
--card-bg-light: rgba(255, 255, 255, 0.85);
|
||||
|
||||
--primary-color-dark: #5271C4;
|
||||
--text-color-dark: #E0E0E0;
|
||||
--card-bg-dark: rgba(40, 40, 40, 0.85);
|
||||
|
||||
--primary-color-winter: #6A82FB;
|
||||
--text-color-winter: #2c3e50;
|
||||
--card-bg-winter: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.top-nav {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
padding: 5px;
|
||||
border-radius: 50px;
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
.theme-switcher {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.theme-btn {
|
||||
background: transparent;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 1.5em;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s, border-color 0.2s;
|
||||
}
|
||||
.theme-btn:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
.theme-btn.active {
|
||||
border-color: white;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-family: 'ZCOOL KuaiLe', cursive;
|
||||
font-size: 3em;
|
||||
margin-bottom: 20px;
|
||||
transition: color 0.5s ease;
|
||||
}
|
||||
|
||||
.joke-stream {
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 25px;
|
||||
}
|
||||
|
||||
.joke-card {
|
||||
border-radius: 20px;
|
||||
padding: 30px 40px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
min-height: 150px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
backdrop-filter: blur(8px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
transition: background-color 0.5s ease, border-color 0.5s ease;
|
||||
}
|
||||
|
||||
#joke-text {
|
||||
font-size: 1.5em;
|
||||
line-height: 1.6;
|
||||
transition: opacity 0.3s, color 0.5s ease;
|
||||
}
|
||||
|
||||
/* --- Theming --- */
|
||||
|
||||
/* Light Theme */
|
||||
[data-theme="light"] .title { color: white; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2); }
|
||||
[data-theme="light"] .joke-card { background-color: var(--card-bg-light); }
|
||||
[data-theme="light"] #joke-text { color: var(--text-color-light); }
|
||||
[data-theme="light"] #new-joke-btn { background-color: var(--primary-color-light); box-shadow: 0 4px 15px rgba(74, 144, 226, 0.4); }
|
||||
[data-theme="light"] footer { color: rgba(255, 255, 255, 0.8); }
|
||||
|
||||
/* Dark Theme */
|
||||
[data-theme="dark"] .title { color: #EAEAEA; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); }
|
||||
[data-theme="dark"] .joke-card { background-color: var(--card-bg-dark); border-color: rgba(255, 255, 255, 0.1); }
|
||||
[data-theme="dark"] #joke-text { color: var(--text-color-dark); }
|
||||
[data-theme="dark"] #new-joke-btn { background-color: var(--primary-color-dark); box-shadow: 0 4px 15px rgba(82, 113, 196, 0.4); }
|
||||
[data-theme="dark"] footer { color: rgba(200, 200, 200, 0.7); }
|
||||
|
||||
/* Winter Theme */
|
||||
[data-theme="winter"] .title { color: #1e3a5f; text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.7); }
|
||||
[data-theme="winter"] .joke-card {
|
||||
background-color: var(--card-bg-winter);
|
||||
border-color: rgba(255, 255, 255, 0.8);
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1), inset 0 0 15px rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
[data-theme="winter"] #joke-text { color: var(--text-color-winter); }
|
||||
[data-theme="winter"] #new-joke-btn { background-color: var(--primary-color-winter); box-shadow: 0 4px 15px rgba(106, 130, 251, 0.4); }
|
||||
[data-theme="winter"] footer { color: #1e3a5f; }
|
||||
|
||||
|
||||
.controls {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
#new-joke-btn {
|
||||
color: white;
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
padding: 15px 35px;
|
||||
border: none;
|
||||
border-radius: 50px;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease, background-color 0.5s ease;
|
||||
}
|
||||
|
||||
#new-joke-btn:hover {
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
#new-joke-btn:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
.interactions {
|
||||
margin-top: 25px;
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.interaction-btn {
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
border: 1px solid rgba(255, 255, 255, 0.9);
|
||||
border-radius: 50%;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
font-size: 1.5em;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s, background-color 0.2s;
|
||||
}
|
||||
|
||||
.interaction-btn:hover {
|
||||
transform: scale(1.1);
|
||||
background: white;
|
||||
}
|
||||
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
font-size: 0.9em;
|
||||
transition: color 0.5s ease;
|
||||
}
|
||||
|
||||
/* Loader */
|
||||
#loader {
|
||||
position: absolute;
|
||||
transition: color 0.5s ease;
|
||||
}
|
||||
[data-theme="light"] #loader { color: var(--primary-color-light); }
|
||||
[data-theme="dark"] #loader { color: var(--primary-color-dark); }
|
||||
[data-theme="winter"] #loader { color: var(--primary-color-winter); }
|
||||
|
||||
.snowflake-loader {
|
||||
font-size: 40px;
|
||||
display: inline-block;
|
||||
animation: spin 1.5s linear infinite;
|
||||
}
|
||||
.snowflake-loader::before {
|
||||
content: '❄';
|
||||
}
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 600px) {
|
||||
.title {
|
||||
font-size: 2.5em;
|
||||
}
|
||||
.joke-card {
|
||||
padding: 25px;
|
||||
}
|
||||
#joke-text {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.top-nav {
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
}
|
||||
58
InfoGenie-frontend/public/60sapi/娱乐消遣/随机冷笑话/index.html
Normal file
58
InfoGenie-frontend/public/60sapi/娱乐消遣/随机冷笑话/index.html
Normal file
@@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>随机冷笑话</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=ZCOOL+KuaiLe&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="css/background.css">
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
</head>
|
||||
<body data-theme="light">
|
||||
<div id="snowflake-container"></div>
|
||||
<div id="frost-overlay"></div>
|
||||
<div class="background-bottom"></div>
|
||||
|
||||
<nav class="top-nav">
|
||||
<div class="theme-switcher">
|
||||
<button class="theme-btn" data-theme-target="light" title="清新风">☀️</button>
|
||||
<button class="theme-btn" data-theme-target="dark" title="暗黑风">🌙</button>
|
||||
<button class="theme-btn" data-theme-target="winter" title="冰雪风">❄️</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1 class="title">冷笑话生成器</h1>
|
||||
</header>
|
||||
|
||||
<main class="joke-card">
|
||||
<div id="loader" class="hidden">
|
||||
<div class="snowflake-loader"></div>
|
||||
<p>思考中...</p>
|
||||
</div>
|
||||
<p id="joke-text">点击下面的按钮,来点冷笑话吧!</p>
|
||||
</main>
|
||||
|
||||
<div class="controls">
|
||||
<button id="new-joke-btn">再来一个</button>
|
||||
</div>
|
||||
|
||||
<div class="interactions">
|
||||
<button class="interaction-btn" id="like-btn" title="好笑">👍</button>
|
||||
<button class="interaction-btn" id="dislike-btn" title="不好笑">👎</button>
|
||||
<button class="interaction-btn" id="collect-btn" title="收藏">⭐️</button>
|
||||
<button class="interaction-btn" id="share-btn" title="分享">🔗</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>© 2024 冷笑话工坊</p>
|
||||
</footer>
|
||||
|
||||
<audio id="wind-sound" src="https://www.soundjay.com/nature/sounds/wind-howl-01.mp3" preload="auto"></audio>
|
||||
<audio id="snow-sound" src="https://www.soundjay.com/nature/sounds/walking-in-snow-01.mp3" preload="auto"></audio>
|
||||
|
||||
<script src="js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
117
InfoGenie-frontend/public/60sapi/娱乐消遣/随机冷笑话/js/script.js
Normal file
117
InfoGenie-frontend/public/60sapi/娱乐消遣/随机冷笑话/js/script.js
Normal file
@@ -0,0 +1,117 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const jokeTextElem = document.getElementById('joke-text');
|
||||
const newJokeBtn = document.getElementById('new-joke-btn');
|
||||
const snowflakeContainer = document.getElementById('snowflake-container');
|
||||
const frostOverlay = document.getElementById('frost-overlay');
|
||||
const windSound = document.getElementById('wind-sound');
|
||||
const snowSound = document.getElementById('snow-sound');
|
||||
const loader = document.getElementById('loader');
|
||||
const themeBtns = document.querySelectorAll('.theme-btn');
|
||||
|
||||
const apiEndpoints = [
|
||||
'https://60s.api.shumengya.top/v2/dad-joke',
|
||||
];
|
||||
let currentApiIndex = 0;
|
||||
|
||||
async function fetchJoke() {
|
||||
jokeTextElem.classList.add('hidden');
|
||||
loader.classList.remove('hidden');
|
||||
|
||||
try {
|
||||
const response = await fetch(apiEndpoints[currentApiIndex]);
|
||||
if (!response.ok) throw new Error('Network response was not ok');
|
||||
|
||||
const data = await response.json();
|
||||
if (data.code === 200 && data.data.content) {
|
||||
updateJokeText(data.data.content);
|
||||
if (document.body.dataset.theme === 'winter' && Math.random() < 0.3) {
|
||||
triggerFrostEffect();
|
||||
}
|
||||
} else {
|
||||
throw new Error('API returned invalid data');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fetch error:', error);
|
||||
currentApiIndex = (currentApiIndex + 1) % apiEndpoints.length;
|
||||
if (currentApiIndex !== 0) {
|
||||
fetchJoke();
|
||||
} else {
|
||||
jokeTextElem.textContent = '冰箱坏了,暂时没有冷笑话...';
|
||||
}
|
||||
} finally {
|
||||
loader.classList.add('hidden');
|
||||
jokeTextElem.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function updateJokeText(text) {
|
||||
jokeTextElem.textContent = '';
|
||||
let i = 0;
|
||||
const typing = setInterval(() => {
|
||||
if (i < text.length) {
|
||||
jokeTextElem.textContent += text.charAt(i);
|
||||
i++;
|
||||
} else {
|
||||
clearInterval(typing);
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
|
||||
function createSnowflakes() {
|
||||
const snowflakeCount = document.body.dataset.theme === 'dark' ? 50 : 30;
|
||||
snowflakeContainer.innerHTML = '';
|
||||
for (let i = 0; i < snowflakeCount; i++) {
|
||||
const snowflake = document.createElement('div');
|
||||
snowflake.className = 'snowflake';
|
||||
snowflake.textContent = '❄️';
|
||||
|
||||
snowflake.style.left = `${Math.random() * 100}vw`;
|
||||
snowflake.style.fontSize = `${Math.random() * 15 + 10}px`;
|
||||
snowflake.style.opacity = Math.random() * 0.5 + 0.3;
|
||||
|
||||
const duration = Math.random() * 10 + 8;
|
||||
const delay = Math.random() * 10;
|
||||
|
||||
snowflake.style.animation = `fall ${duration}s linear ${delay}s infinite`;
|
||||
|
||||
snowflakeContainer.appendChild(snowflake);
|
||||
}
|
||||
}
|
||||
|
||||
function triggerFrostEffect() {
|
||||
frostOverlay.classList.add('is-frosted');
|
||||
windSound.play().catch(e => console.error("Audio play failed:", e));
|
||||
setTimeout(() => {
|
||||
frostOverlay.classList.remove('is-frosted');
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function setTheme(theme) {
|
||||
document.body.dataset.theme = theme;
|
||||
localStorage.setItem('joke-theme', theme);
|
||||
|
||||
themeBtns.forEach(btn => {
|
||||
btn.classList.toggle('active', btn.dataset.themeTarget === theme);
|
||||
});
|
||||
|
||||
if (theme === 'winter') {
|
||||
snowSound.play().catch(e => console.error("Audio play failed:", e));
|
||||
}
|
||||
|
||||
// Recreate snowflakes for theme-specific density
|
||||
createSnowflakes();
|
||||
}
|
||||
|
||||
themeBtns.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
setTheme(btn.dataset.themeTarget);
|
||||
});
|
||||
});
|
||||
|
||||
newJokeBtn.addEventListener('click', fetchJoke);
|
||||
|
||||
// Initial setup
|
||||
const savedTheme = localStorage.getItem('joke-theme') || 'light';
|
||||
setTheme(savedTheme);
|
||||
fetchJoke();
|
||||
});
|
||||
1
InfoGenie-frontend/public/60sapi/娱乐消遣/随机冷笑话/接口集合.json
Normal file
1
InfoGenie-frontend/public/60sapi/娱乐消遣/随机冷笑话/接口集合.json
Normal file
@@ -0,0 +1 @@
|
||||
["https://60s.api.shumengya.top"]
|
||||
8
InfoGenie-frontend/public/60sapi/娱乐消遣/随机冷笑话/返回接口.json
Normal file
8
InfoGenie-frontend/public/60sapi/娱乐消遣/随机冷笑话/返回接口.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841",
|
||||
"data": {
|
||||
"index": 121,
|
||||
"content": "这个世界上谁最懂猪?蜘蛛(知猪)人。"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
body {
|
||||
background-color: #1a1a1a;
|
||||
color: #e0e0e0;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#bg-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -2;
|
||||
overflow: hidden;
|
||||
transition: transform 0.2s ease-out;
|
||||
}
|
||||
|
||||
.floating-emoji {
|
||||
position: absolute;
|
||||
user-select: none;
|
||||
opacity: 0;
|
||||
animation-iteration-count: infinite;
|
||||
animation-timing-function: linear;
|
||||
}
|
||||
|
||||
@keyframes float-top-to-bottom {
|
||||
0% { transform: translateY(-10vh) rotate(0deg); opacity: 0; }
|
||||
10%, 90% { opacity: 0.7; }
|
||||
100% { transform: translateY(110vh) rotate(360deg); opacity: 0; }
|
||||
}
|
||||
|
||||
@keyframes float-bottom-to-top {
|
||||
0% { transform: translateY(110vh) rotate(0deg); opacity: 0; }
|
||||
10%, 90% { opacity: 0.7; }
|
||||
100% { transform: translateY(-10vh) rotate(360deg); opacity: 0; }
|
||||
}
|
||||
|
||||
@keyframes float-left-to-right {
|
||||
0% { transform: translateX(-10vw) rotate(0deg); opacity: 0; }
|
||||
10%, 90% { opacity: 0.7; }
|
||||
100% { transform: translateX(110vw) rotate(360deg); opacity: 0; }
|
||||
}
|
||||
|
||||
@keyframes float-right-to-left {
|
||||
0% { transform: translateX(110vw) rotate(0deg); opacity: 0; }
|
||||
10%, 90% { opacity: 0.7; }
|
||||
100% { transform: translateX(-10vw) rotate(360deg); opacity: 0; }
|
||||
}
|
||||
|
||||
.text-fragment {
|
||||
position: absolute;
|
||||
font-size: 24px;
|
||||
color: rgba(255, 0, 255, 0.4);
|
||||
opacity: 0;
|
||||
animation: float-fragment 15s linear infinite, fade-in-out 15s linear infinite;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@keyframes float-fragment {
|
||||
0% { transform: translate(0, 0) rotate(0deg); }
|
||||
25% { transform: translate(20px, 40px) rotate(15deg); }
|
||||
50% { transform: translate(-30px, -10px) rotate(-10deg); }
|
||||
75% { transform: translate(10px, -30px) rotate(5deg); }
|
||||
100% { transform: translate(0, 0) rotate(0deg); }
|
||||
}
|
||||
|
||||
@keyframes fade-in-out {
|
||||
0%, 100% { opacity: 0; }
|
||||
10%, 90% { opacity: 0.4; }
|
||||
}
|
||||
|
||||
.screen-crack {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M 100 100 L 0 0 M 100 100 L 200 0 M 100 100 L 50 200 M 100 100 L 150 200" stroke="rgba(255,255,255,0.5)" stroke-width="1" fill="none"/></svg>');
|
||||
opacity: 0;
|
||||
animation: flicker-crack 25s steps(1, end) infinite;
|
||||
}
|
||||
|
||||
@keyframes flicker-crack {
|
||||
0%, 100% { opacity: 0; }
|
||||
50% { opacity: 0.3; }
|
||||
51% { opacity: 0; }
|
||||
75% { opacity: 0.2; }
|
||||
76% { opacity: 0; }
|
||||
}
|
||||
235
InfoGenie-frontend/public/60sapi/娱乐消遣/随机发病文学/css/style.css
Normal file
235
InfoGenie-frontend/public/60sapi/娱乐消遣/随机发病文学/css/style.css
Normal file
@@ -0,0 +1,235 @@
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.content-card {
|
||||
background: rgba(20, 20, 20, 0.7);
|
||||
border: none;
|
||||
padding: 40px;
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
backdrop-filter: blur(5px);
|
||||
position: relative;
|
||||
clip-path: polygon(2% 5%, 97% 0%, 100% 95%, 0% 100%);
|
||||
}
|
||||
|
||||
.body-animated .content-card {
|
||||
animation: tremble 0.4s infinite, glitch-shadow 1.5s steps(1, end) infinite;
|
||||
}
|
||||
|
||||
@keyframes tremble {
|
||||
0% { clip-path: polygon(2% 5%, 97% 0%, 100% 95%, 0% 100%); }
|
||||
25% { clip-path: polygon(2% 5%, 98% 2%, 99% 100%, 1% 98%); }
|
||||
50% { clip-path: polygon(3% 4%, 96% 1%, 100% 96%, 2% 100%); }
|
||||
75% { clip-path: polygon(1% 6%, 97% 3%, 98% 95%, 0% 99%); }
|
||||
100% { clip-path: polygon(2% 5%, 97% 0%, 100% 95%, 0% 100%); }
|
||||
}
|
||||
|
||||
@keyframes glitch-shadow {
|
||||
0% {
|
||||
box-shadow:
|
||||
0 0 8px rgba(255, 0, 255, 0.5),
|
||||
inset 0 0 8px rgba(255, 0, 255, 0.4);
|
||||
}
|
||||
33% {
|
||||
box-shadow:
|
||||
0 0 8px rgba(0, 255, 255, 0.5),
|
||||
inset 0 0 8px rgba(0, 255, 255, 0.4);
|
||||
}
|
||||
66% {
|
||||
box-shadow:
|
||||
0 0 8px rgba(0, 255, 0, 0.5),
|
||||
inset 0 0 8px rgba(0, 255, 0, 0.4);
|
||||
}
|
||||
100% {
|
||||
box-shadow:
|
||||
0 0 8px rgba(255, 0, 255, 0.5),
|
||||
inset 0 0 8px rgba(255, 0, 255, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
#literature-text {
|
||||
font-size: 1.2em;
|
||||
line-height: 1.8;
|
||||
min-height: 100px;
|
||||
color: #e0e0e0;
|
||||
text-shadow: 0 0 5px rgba(0, 255, 135, 0.5);
|
||||
animation: text-flicker 15s linear infinite;
|
||||
}
|
||||
|
||||
.body-animated #literature-text {
|
||||
animation: text-flicker 15s linear infinite, text-shadow-glitch 2s steps(1, end) infinite;
|
||||
}
|
||||
|
||||
@keyframes text-flicker {
|
||||
0%, 100% { opacity: 1; }
|
||||
50.0% { opacity: 0.95; }
|
||||
50.5% { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes text-shadow-glitch {
|
||||
0% {
|
||||
text-shadow:
|
||||
1px 0 0 rgba(255,0,255,0.5),
|
||||
-1px 0 0 rgba(0,255,255,0.5);
|
||||
}
|
||||
10% {
|
||||
text-shadow:
|
||||
-1px 0 0 rgba(255,0,255,0.5),
|
||||
1px 0 0 rgba(0,255,255,0.5);
|
||||
}
|
||||
11%, 100% {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.controls {
|
||||
margin-top: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
#new-literature-btn {
|
||||
background-color: #ff00ff;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 12px 25px;
|
||||
font-size: 1em;
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
box-shadow: 0 0 10px #ff00ff, 0 0 20px #ff00ff;
|
||||
}
|
||||
|
||||
#new-literature-btn:hover {
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 0 15px #ff00ff, 0 0 30px #ff00ff;
|
||||
}
|
||||
|
||||
#new-literature-btn:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
/* Animation Toggle Switch */
|
||||
.switch-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.switch input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
background-color: #ff00ff;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
transform: translateX(26px);
|
||||
}
|
||||
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* Glitch Overlay & Animations */
|
||||
#glitch-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.body-animated #glitch-overlay {
|
||||
animation: color-shift 15s steps(1, end) infinite;
|
||||
}
|
||||
|
||||
@keyframes color-shift {
|
||||
0%, 100% { background: transparent; }
|
||||
10% { background: rgba(255, 0, 0, 0.05); }
|
||||
10.1% { background: transparent; }
|
||||
20% { background: rgba(0, 255, 0, 0.05); }
|
||||
20.1% { background: transparent; }
|
||||
30% { background: rgba(0, 0, 255, 0.05); }
|
||||
30.1% { background: transparent; }
|
||||
}
|
||||
|
||||
.flicker-block {
|
||||
position: absolute;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.body-animated .flicker-block {
|
||||
animation: flicker 3s infinite;
|
||||
}
|
||||
|
||||
@keyframes flicker {
|
||||
0%, 100% { opacity: 0; }
|
||||
50% { opacity: 1; }
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.content-card {
|
||||
padding: 20px;
|
||||
}
|
||||
#literature-text {
|
||||
font-size: 1em;
|
||||
}
|
||||
.controls {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
34
InfoGenie-frontend/public/60sapi/娱乐消遣/随机发病文学/index.html
Normal file
34
InfoGenie-frontend/public/60sapi/娱乐消遣/随机发病文学/index.html
Normal file
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>随机发病文学</title>
|
||||
<link rel="stylesheet" href="css/background.css">
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="bg-container">
|
||||
</div>
|
||||
<div id="glitch-overlay"></div>
|
||||
|
||||
<div class="container">
|
||||
<div class="content-card">
|
||||
<p id="literature-text">正在加载发病文学...</p>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<button id="new-literature-btn">再疯一次</button>
|
||||
<div class="switch-container">
|
||||
<label for="animation-toggle">关闭动画</label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="animation-toggle" checked>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
147
InfoGenie-frontend/public/60sapi/娱乐消遣/随机发病文学/js/script.js
Normal file
147
InfoGenie-frontend/public/60sapi/娱乐消遣/随机发病文学/js/script.js
Normal file
@@ -0,0 +1,147 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const literatureTextElem = document.getElementById('literature-text');
|
||||
const newLiteratureBtn = document.getElementById('new-literature-btn');
|
||||
const animationToggle = document.getElementById('animation-toggle');
|
||||
const bgContainer = document.getElementById('bg-container');
|
||||
const body = document.body;
|
||||
|
||||
const apiEndpoints = [
|
||||
'https://60s.api.shumengya.top/v2/fabing',
|
||||
// Add fallback APIs here if available
|
||||
];
|
||||
|
||||
let currentApiIndex = 0;
|
||||
|
||||
async function fetchLiterature() {
|
||||
literatureTextElem.textContent = '正在卖力发疯中...';
|
||||
literatureTextElem.style.opacity = '0.5';
|
||||
|
||||
try {
|
||||
const response = await fetch(apiEndpoints[currentApiIndex]);
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
const data = await response.json();
|
||||
if (data.code === 200) {
|
||||
literatureTextElem.textContent = data.data.saying;
|
||||
} else {
|
||||
throw new Error('API returned an error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fetch error:', error);
|
||||
currentApiIndex = (currentApiIndex + 1) % apiEndpoints.length;
|
||||
if (currentApiIndex !== 0) {
|
||||
fetchLiterature(); // Retry with the next API
|
||||
} else {
|
||||
literatureTextElem.textContent = '疯不起来了,请稍后再试。';
|
||||
}
|
||||
} finally {
|
||||
literatureTextElem.style.opacity = '1';
|
||||
}
|
||||
}
|
||||
|
||||
function createFloatingEmojis() {
|
||||
const existingEmojis = bgContainer.querySelectorAll('.floating-emoji');
|
||||
existingEmojis.forEach(e => e.remove());
|
||||
|
||||
const emojis = ['🤯', '😵', '🤪', '🥴', '🤡', '👹', '👻', '💀', '💥', '🔥', '🌪️', '😵💫'];
|
||||
const animationNames = ['float-top-to-bottom', 'float-bottom-to-top', 'float-left-to-right', 'float-right-to-left'];
|
||||
const emojiCount = 25;
|
||||
|
||||
for (let i = 0; i < emojiCount; i++) {
|
||||
const emojiEl = document.createElement('div');
|
||||
emojiEl.className = 'floating-emoji';
|
||||
emojiEl.textContent = emojis[Math.floor(Math.random() * emojis.length)];
|
||||
|
||||
const animationName = animationNames[Math.floor(Math.random() * animationNames.length)];
|
||||
emojiEl.style.animationName = animationName;
|
||||
emojiEl.style.animationDuration = `${Math.random() * 10 + 15}s`; // 15-25 seconds
|
||||
emojiEl.style.animationDelay = `${Math.random() * 20}s`;
|
||||
emojiEl.style.fontSize = `${Math.random() * 20 + 20}px`;
|
||||
|
||||
// Set initial position based on animation direction
|
||||
if (animationName.includes('top') || animationName.includes('bottom')) { // Vertical movement
|
||||
emojiEl.style.left = `${Math.random() * 100}vw`;
|
||||
} else { // Horizontal movement
|
||||
emojiEl.style.top = `${Math.random() * 100}vh`;
|
||||
}
|
||||
|
||||
bgContainer.appendChild(emojiEl);
|
||||
}
|
||||
}
|
||||
|
||||
function createFragments() {
|
||||
const existingFragments = bgContainer.querySelectorAll('.text-fragment');
|
||||
existingFragments.forEach(f => f.remove());
|
||||
|
||||
const fragments = ['我', '疯', '了', '?', '!', '…', '救命', '为什么', '好烦', '啊啊啊'];
|
||||
for (let i = 0; i < 20; i++) {
|
||||
const frag = document.createElement('div');
|
||||
frag.className = 'text-fragment';
|
||||
frag.textContent = fragments[Math.floor(Math.random() * fragments.length)];
|
||||
frag.style.top = `${Math.random() * 100}%`;
|
||||
frag.style.left = `${Math.random() * 100}%`;
|
||||
frag.style.animationDelay = `${Math.random() * 15}s`;
|
||||
frag.style.fontSize = `${Math.random() * 12 + 12}px`;
|
||||
bgContainer.appendChild(frag);
|
||||
}
|
||||
}
|
||||
|
||||
function createCracks() {
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const crack = document.createElement('div');
|
||||
crack.className = 'screen-crack';
|
||||
crack.style.top = `${Math.random() * 80}%`;
|
||||
crack.style.left = `${Math.random() * 80}%`;
|
||||
crack.style.transform = `rotate(${Math.random() * 360}deg)`;
|
||||
crack.style.animationDelay = `${Math.random() * 25}s`;
|
||||
bgContainer.appendChild(crack);
|
||||
}
|
||||
}
|
||||
|
||||
function createFlickerBlocks() {
|
||||
const glitchOverlay = document.getElementById('glitch-overlay');
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const block = document.createElement('div');
|
||||
block.className = 'flicker-block';
|
||||
block.style.width = `${Math.random() * 100 + 50}px`;
|
||||
block.style.height = `${Math.random() * 100 + 50}px`;
|
||||
block.style.top = `${Math.random() * 90}%`;
|
||||
block.style.left = `${Math.random() * 90}%`;
|
||||
block.style.animationDuration = `${Math.random() * 2 + 2}s`;
|
||||
block.style.animationDelay = `${Math.random() * 3}s`;
|
||||
glitchOverlay.appendChild(block);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleAnimations() {
|
||||
if (animationToggle.checked) {
|
||||
body.classList.add('body-animated');
|
||||
} else {
|
||||
body.classList.remove('body-animated');
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', (e) => {
|
||||
if (!animationToggle.checked) return;
|
||||
const x = (window.innerWidth / 2) - e.pageX;
|
||||
const y = (window.innerHeight / 2) - e.pageY;
|
||||
bgContainer.style.transform = `translateX(${x / 50}px) translateY(${y / 50}px)`;
|
||||
});
|
||||
|
||||
newLiteratureBtn.addEventListener('click', fetchLiterature);
|
||||
animationToggle.addEventListener('change', toggleAnimations);
|
||||
|
||||
// Initial setup
|
||||
createFloatingEmojis();
|
||||
createFragments();
|
||||
createCracks();
|
||||
createFlickerBlocks();
|
||||
toggleAnimations();
|
||||
fetchLiterature();
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
createFloatingEmojis();
|
||||
createFragments();
|
||||
});
|
||||
});
|
||||
1
InfoGenie-frontend/public/60sapi/娱乐消遣/随机发病文学/接口集合.json
Normal file
1
InfoGenie-frontend/public/60sapi/娱乐消遣/随机发病文学/接口集合.json
Normal file
@@ -0,0 +1 @@
|
||||
["https://60s.api.shumengya.top"]
|
||||
8
InfoGenie-frontend/public/60sapi/娱乐消遣/随机发病文学/返回接口.json
Normal file
8
InfoGenie-frontend/public/60sapi/娱乐消遣/随机发病文学/返回接口.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841",
|
||||
"data": {
|
||||
"index": 347,
|
||||
"duanzi": "我不想读书,主要是因为家里牛啊,猪啊羊啊都没人喂。"
|
||||
}
|
||||
}
|
||||
251
InfoGenie-frontend/public/60sapi/娱乐消遣/随机唱歌音频/css/style.css
Normal file
251
InfoGenie-frontend/public/60sapi/娱乐消遣/随机唱歌音频/css/style.css
Normal file
@@ -0,0 +1,251 @@
|
||||
/* 随机唱歌音频 - 淡绿色清新风格样式 */
|
||||
|
||||
/* 重置样式 */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #a8e6cf 0%, #dcedc1 50%, #ffd3a5 100%);
|
||||
min-height: 100vh;
|
||||
color: #2d5016;
|
||||
line-height: 1.6;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* 头部 */
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
border-radius: 20px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 25px rgba(45, 80, 22, 0.08);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 2rem;
|
||||
color: #2d5016;
|
||||
margin-bottom: 10px;
|
||||
font-weight: 700;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.header p {
|
||||
color: #5a7c65;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* 用户卡片 */
|
||||
.user-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
padding: 16px;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 4px 18px rgba(45, 80, 22, 0.08);
|
||||
margin-bottom: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 3px solid rgba(129, 199, 132, 0.5);
|
||||
}
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.nickname {
|
||||
font-weight: 700;
|
||||
font-size: 1.1rem;
|
||||
color: #2d5016;
|
||||
}
|
||||
|
||||
.meta {
|
||||
color: #5a7c65;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* 歌曲信息 */
|
||||
.song-card {
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
padding: 16px;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 4px 18px rgba(45, 80, 22, 0.08);
|
||||
margin-bottom: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.song-title {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 8px;
|
||||
color: #1b5e20;
|
||||
}
|
||||
|
||||
.song-meta {
|
||||
color: #5a7c65;
|
||||
font-size: 0.95rem;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* 歌词 */
|
||||
.lyrics {
|
||||
background: rgba(129, 199, 132, 0.1);
|
||||
border-radius: 12px;
|
||||
padding: 12px;
|
||||
max-height: 220px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.lyrics p {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
/* 音频播放器卡片 */
|
||||
.audio-card {
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
padding: 16px;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 4px 18px rgba(45, 80, 22, 0.08);
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.audio-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: linear-gradient(135deg, #81c784 0%, #66bb6a 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.25s ease;
|
||||
box-shadow: 0 4px 12px rgba(129, 199, 132, 0.35);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 18px rgba(129, 199, 132, 0.45);
|
||||
}
|
||||
|
||||
.info {
|
||||
color: #5a7c65;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* 加载与错误 */
|
||||
.loading, .error {
|
||||
text-align: center;
|
||||
padding: 30px;
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 5px 20px rgba(45, 80, 22, 0.08);
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: 4px solid #e8f5e8;
|
||||
border-top: 4px solid #81c784;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0 auto 18px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* 动画 */
|
||||
.fade-in {
|
||||
animation: fadeIn 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(10px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* 平板端适配 */
|
||||
@media (max-width: 1024px) and (min-width: 768px) {
|
||||
.container { padding: 16px; }
|
||||
.header h1 { font-size: 1.8rem; }
|
||||
}
|
||||
|
||||
/* 手机端优先优化 */
|
||||
@media (max-width: 767px) {
|
||||
.container { padding: 12px; }
|
||||
.header { padding: 18px; }
|
||||
.header h1 { font-size: 1.6rem; gap: 8px; }
|
||||
|
||||
.user-card {
|
||||
padding: 16px;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.song-card, .audio-card {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.lyrics {
|
||||
max-height: 180px;
|
||||
text-align: left;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.audio-actions {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.info {
|
||||
text-align: center;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
max-width: 200px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
67
InfoGenie-frontend/public/60sapi/娱乐消遣/随机唱歌音频/index.html
Normal file
67
InfoGenie-frontend/public/60sapi/娱乐消遣/随机唱歌音频/index.html
Normal file
@@ -0,0 +1,67 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>随机唱歌音频 - 60s API 集合</title>
|
||||
<meta name="description" content="随机唱歌音频,数据源自 60s.viki.moe,提供用户信息、歌曲信息、歌词与音频播放。" />
|
||||
|
||||
<link rel="stylesheet" href="./css/style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header class="header">
|
||||
<h1>
|
||||
🎵 随机唱歌音频
|
||||
</h1>
|
||||
<p>数据来自官方/权威源头,以确保稳定与实时 · 支持本地数据回退</p>
|
||||
</header>
|
||||
|
||||
<!-- 加载与错误状态 -->
|
||||
<section id="loading" class="loading">
|
||||
<div class="spinner"></div>
|
||||
<p>正在加载中,请稍候…</p>
|
||||
</section>
|
||||
|
||||
<section id="error" class="error" style="display: none;">
|
||||
<p>获取数据失败,请稍后重试</p>
|
||||
</section>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<main id="content" style="display: none;" class="fade-in">
|
||||
<!-- 用户信息 -->
|
||||
<div class="user-card">
|
||||
<img id="avatar" class="avatar" src="" alt="用户头像" />
|
||||
<div class="user-info">
|
||||
<div class="nickname" id="nickname">-</div>
|
||||
<div class="meta">性别:<span id="gender">-</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 歌曲信息 -->
|
||||
<div class="song-card">
|
||||
<div class="song-title" id="song-title">-</div>
|
||||
<div class="song-meta" id="song-meta">-</div>
|
||||
<div class="lyrics" id="lyrics"></div>
|
||||
</div>
|
||||
|
||||
<!-- 音频播放 -->
|
||||
<div class="audio-card">
|
||||
<audio id="audio" controls style="width: 100%;"></audio>
|
||||
<div class="audio-actions">
|
||||
<button class="btn" id="refresh-btn">换一首</button>
|
||||
<div class="info">
|
||||
❤ 喜欢:<span id="like-count">-</span>
|
||||
· ⏱ 时长:<span id="duration">--:--</span>
|
||||
· 🗓 发布:<span id="publish-time">-</span>
|
||||
· 🔗 <a id="link" href="#" class="btn" style="padding: 6px 10px; border-radius: 8px; background: #81c784;">查看原帖</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="./js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
252
InfoGenie-frontend/public/60sapi/娱乐消遣/随机唱歌音频/js/script.js
Normal file
252
InfoGenie-frontend/public/60sapi/娱乐消遣/随机唱歌音频/js/script.js
Normal file
@@ -0,0 +1,252 @@
|
||||
// 随机唱歌音频 页面脚本
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const API = {
|
||||
endpoints: [],
|
||||
currentIndex: 0,
|
||||
params: {
|
||||
encoding: 'json'
|
||||
},
|
||||
localFallback: '返回接口.json',
|
||||
// 初始化API接口列表
|
||||
async init() {
|
||||
try {
|
||||
const res = await fetch('./接口集合.json');
|
||||
const endpoints = await res.json();
|
||||
this.endpoints = endpoints.map(endpoint => `${endpoint}/v2/changya`);
|
||||
} catch (e) {
|
||||
// 如果无法加载接口集合,使用默认接口
|
||||
this.endpoints = ['https://60s.api.shumengya.top/v2/changya'];
|
||||
}
|
||||
},
|
||||
// 获取当前接口URL
|
||||
getCurrentUrl() {
|
||||
if (this.endpoints.length === 0) return null;
|
||||
const url = new URL(this.endpoints[this.currentIndex]);
|
||||
Object.entries(this.params).forEach(([k, v]) => url.searchParams.append(k, v));
|
||||
return url.toString();
|
||||
},
|
||||
// 切换到下一个接口
|
||||
switchToNext() {
|
||||
this.currentIndex = (this.currentIndex + 1) % this.endpoints.length;
|
||||
return this.currentIndex < this.endpoints.length;
|
||||
},
|
||||
// 重置到第一个接口
|
||||
reset() {
|
||||
this.currentIndex = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// DOM 元素引用
|
||||
const els = {
|
||||
loading: null,
|
||||
error: null,
|
||||
container: null,
|
||||
avatar: null,
|
||||
nickname: null,
|
||||
gender: null,
|
||||
songTitle: null,
|
||||
songMeta: null,
|
||||
lyrics: null,
|
||||
audio: null,
|
||||
likeCount: null,
|
||||
publishTime: null,
|
||||
link: null,
|
||||
refreshBtn: null,
|
||||
};
|
||||
|
||||
function initDom() {
|
||||
els.loading = document.getElementById('loading');
|
||||
els.error = document.getElementById('error');
|
||||
els.container = document.getElementById('content');
|
||||
|
||||
els.avatar = document.getElementById('avatar');
|
||||
els.nickname = document.getElementById('nickname');
|
||||
els.gender = document.getElementById('gender');
|
||||
els.songTitle = document.getElementById('song-title');
|
||||
els.songMeta = document.getElementById('song-meta');
|
||||
els.lyrics = document.getElementById('lyrics');
|
||||
|
||||
els.audio = document.getElementById('audio');
|
||||
els.likeCount = document.getElementById('like-count');
|
||||
els.publishTime = document.getElementById('publish-time');
|
||||
els.link = document.getElementById('link');
|
||||
els.refreshBtn = document.getElementById('refresh-btn');
|
||||
}
|
||||
|
||||
function showLoading() {
|
||||
els.loading.style.display = 'block';
|
||||
els.error.style.display = 'none';
|
||||
els.container.style.display = 'none';
|
||||
}
|
||||
|
||||
function showError(msg) {
|
||||
els.loading.style.display = 'none';
|
||||
els.error.style.display = 'block';
|
||||
els.container.style.display = 'none';
|
||||
els.error.querySelector('p').textContent = msg || '获取数据失败,请稍后重试';
|
||||
}
|
||||
|
||||
function showContent() {
|
||||
els.loading.style.display = 'none';
|
||||
els.error.style.display = 'none';
|
||||
els.container.style.display = 'block';
|
||||
}
|
||||
|
||||
function formatDuration(ms) {
|
||||
if (!ms && ms !== 0) return '';
|
||||
const totalSeconds = Math.floor(ms / 1000);
|
||||
const m = Math.floor(totalSeconds / 60).toString().padStart(2, '0');
|
||||
const s = (totalSeconds % 60).toString().padStart(2, '0');
|
||||
return `${m}:${s}`;
|
||||
}
|
||||
|
||||
function safeText(text) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text == null ? '' : String(text);
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
async function fetchFromAPI() {
|
||||
// 初始化API接口列表
|
||||
await API.init();
|
||||
|
||||
// 重置API索引到第一个接口
|
||||
API.reset();
|
||||
|
||||
// 尝试所有API接口
|
||||
for (let i = 0; i < API.endpoints.length; i++) {
|
||||
try {
|
||||
const url = API.getCurrentUrl();
|
||||
console.log(`尝试接口 ${i + 1}/${API.endpoints.length}: ${url}`);
|
||||
|
||||
const resp = await fetch(url, {
|
||||
cache: 'no-store',
|
||||
timeout: 10000 // 10秒超时
|
||||
});
|
||||
|
||||
if (!resp.ok) {
|
||||
throw new Error(`HTTP ${resp.status}: ${resp.statusText}`);
|
||||
}
|
||||
|
||||
const data = await resp.json();
|
||||
|
||||
if (data && data.code === 200) {
|
||||
console.log(`接口 ${i + 1} 请求成功`);
|
||||
return data;
|
||||
}
|
||||
|
||||
throw new Error(data && data.message ? data.message : '接口返回异常');
|
||||
|
||||
} catch (e) {
|
||||
console.warn(`接口 ${i + 1} 失败:`, e.message);
|
||||
|
||||
// 如果不是最后一个接口,切换到下一个
|
||||
if (i < API.endpoints.length - 1) {
|
||||
API.switchToNext();
|
||||
continue;
|
||||
}
|
||||
|
||||
// 所有接口都失败了
|
||||
console.warn('所有远程接口都失败,尝试本地数据');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchFromLocal() {
|
||||
try {
|
||||
const resp = await fetch(API.localFallback + `?t=${Date.now()}`);
|
||||
if (!resp.ok) throw new Error(`本地文件HTTP ${resp.status}`);
|
||||
const data = await resp.json();
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error('读取本地返回接口.json失败:', e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function render(data) {
|
||||
const d = data?.data || {};
|
||||
const user = d.user || {};
|
||||
const song = d.song || {};
|
||||
const audio = d.audio || {};
|
||||
|
||||
// 用户信息
|
||||
els.avatar.src = user.avatar_url || '';
|
||||
els.avatar.alt = (user.nickname || '用户') + ' 头像';
|
||||
els.nickname.textContent = user.nickname || '未知用户';
|
||||
els.gender.textContent = user.gender === 'female' ? '女' : user.gender === 'male' ? '男' : '未知';
|
||||
|
||||
// 歌曲信息
|
||||
els.songTitle.textContent = song.name || '未知歌曲';
|
||||
els.songMeta.textContent = song.singer ? `演唱:${song.singer}` : '';
|
||||
|
||||
els.lyrics.innerHTML = '';
|
||||
if (Array.isArray(song.lyrics)) {
|
||||
const frag = document.createDocumentFragment();
|
||||
song.lyrics.forEach(line => {
|
||||
const p = document.createElement('p');
|
||||
p.innerHTML = safeText(line);
|
||||
frag.appendChild(p);
|
||||
});
|
||||
els.lyrics.appendChild(frag);
|
||||
}
|
||||
|
||||
// 音频
|
||||
els.audio.src = audio.url || '';
|
||||
els.audio.preload = 'none';
|
||||
|
||||
// 其他信息
|
||||
els.likeCount.textContent = typeof audio.like_count === 'number' ? audio.like_count : '-';
|
||||
const publish = audio.publish || (audio.publish_at ? new Date(audio.publish_at).toLocaleString() : '');
|
||||
els.publishTime.textContent = publish;
|
||||
els.link.href = audio.link || '#';
|
||||
els.link.target = '_blank';
|
||||
|
||||
// 时长信息
|
||||
const durationEl = document.getElementById('duration');
|
||||
durationEl.textContent = formatDuration(audio.duration);
|
||||
|
||||
showContent();
|
||||
}
|
||||
|
||||
async function load() {
|
||||
showLoading();
|
||||
try {
|
||||
// 先尝试远程API
|
||||
const data = await fetchFromAPI();
|
||||
if (data) {
|
||||
render(data);
|
||||
return;
|
||||
}
|
||||
|
||||
// 远程API失败,尝试本地数据
|
||||
const localData = await fetchFromLocal();
|
||||
if (localData) {
|
||||
render(localData);
|
||||
return;
|
||||
}
|
||||
|
||||
// 都失败了
|
||||
showError('获取数据失败,请稍后重试');
|
||||
} catch (e) {
|
||||
console.error('加载数据时发生错误:', e);
|
||||
showError('获取数据失败,请稍后重试');
|
||||
}
|
||||
}
|
||||
|
||||
function bindEvents() {
|
||||
if (els.refreshBtn) {
|
||||
els.refreshBtn.addEventListener('click', load);
|
||||
}
|
||||
// 快捷键 Ctrl+R 刷新(不拦截浏览器默认刷新)
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initDom();
|
||||
bindEvents();
|
||||
load();
|
||||
});
|
||||
})();
|
||||
3
InfoGenie-frontend/public/60sapi/娱乐消遣/随机唱歌音频/接口集合.json
Normal file
3
InfoGenie-frontend/public/60sapi/娱乐消遣/随机唱歌音频/接口集合.json
Normal file
@@ -0,0 +1,3 @@
|
||||
[
|
||||
"https://60s.api.shumengya.top"
|
||||
]
|
||||
32
InfoGenie-frontend/public/60sapi/娱乐消遣/随机唱歌音频/返回接口.json
Normal file
32
InfoGenie-frontend/public/60sapi/娱乐消遣/随机唱歌音频/返回接口.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841",
|
||||
"data": {
|
||||
"user": {
|
||||
"nickname": "𝑮𝑺_迷鹿_",
|
||||
"gender": "female",
|
||||
"avatar_url": "http://img-cdn.api.singduck.cn/user-img/6afbebcfae6144478c150d0c1d0d5899.jpg"
|
||||
},
|
||||
"song": {
|
||||
"name": "恶作剧",
|
||||
"singer": "王蓝茵",
|
||||
"lyrics": [
|
||||
"我想我会开始想念你",
|
||||
"可是我刚刚才遇见了你",
|
||||
"我怀疑这奇遇只是个恶作剧",
|
||||
"我想我已慢慢喜欢你",
|
||||
"因为我拥有爱情的勇气",
|
||||
"我任性投入你给的恶作剧",
|
||||
"你给的恶作剧"
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"url": "http://audio-cdn.api.singduck.cn/ugc/220929_965696173_b822a290c553.wav?auth_key=1755845643-0-0-4029539b73e17337dcac49cc4e0ecfcc",
|
||||
"duration": 35050,
|
||||
"like_count": 955,
|
||||
"link": "https://m.api.singduck.cn/user-piece/toGZlBfZbukck2sHb",
|
||||
"publish": "2022/09/29 18:33:51",
|
||||
"publish_at": 1664447631000
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
transition: background 0.5s ease;
|
||||
}
|
||||
|
||||
/* Hand-drawn Comic Theme Background - NEW VIBRANT VERSION */
|
||||
body.theme-comic {
|
||||
background: linear-gradient(-45deg, #ff7e5f, #feb47b, #ffcc80, #ffecb3);
|
||||
background-size: 400% 400%;
|
||||
animation: gradientBG 15s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes gradientBG {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Placeholder for Emoji Theme Background */
|
||||
body.theme-emoji {
|
||||
background-color: #fffde7;
|
||||
}
|
||||
|
||||
/* Placeholder for Retro TV Theme Background */
|
||||
body.theme-retro {
|
||||
background-color: #3d2b1f;
|
||||
}
|
||||
199
InfoGenie-frontend/public/60sapi/娱乐消遣/随机搞笑段子/css/style.css
Normal file
199
InfoGenie-frontend/public/60sapi/娱乐消遣/随机搞笑段子/css/style.css
Normal file
@@ -0,0 +1,199 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Zhi+Mang+Xing&display=swap');
|
||||
|
||||
/* --- General & Theme Switcher --- */
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.theme-switcher {
|
||||
position: fixed;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
padding: 5px;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.theme-icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
border: 2px solid transparent;
|
||||
}
|
||||
.theme-icon.active {
|
||||
border-color: #ff7043;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
/* --- Comic Theme Styles --- */
|
||||
.theme-comic header h1 {
|
||||
font-family: 'Zhi Mang Xing', cursive;
|
||||
font-size: 4em;
|
||||
color: #d84315; /* Deep Orange */
|
||||
text-shadow: 2px 2px 0 #fff;
|
||||
margin: 0.2em 0;
|
||||
}
|
||||
|
||||
.theme-comic .divider {
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, #ffca28, #ff7043, #29b6f6, #66bb6a);
|
||||
border-radius: 3px;
|
||||
margin: 20px auto;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.theme-comic .joke-card {
|
||||
background: rgba(255, 255, 255, 0.85); /* White with transparency */
|
||||
backdrop-filter: blur(5px);
|
||||
border-radius: 15px;
|
||||
padding: 40px;
|
||||
min-height: 200px;
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
transform: rotate(-1deg);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
.theme-comic .joke-card:hover {
|
||||
transform: rotate(1deg) scale(1.02);
|
||||
}
|
||||
|
||||
.theme-comic .joke-text {
|
||||
font-family: 'Zhi Mang Xing', cursive;
|
||||
font-size: 2em;
|
||||
line-height: 1.6;
|
||||
color: #5d4037;
|
||||
}
|
||||
|
||||
.theme-comic .new-joke-btn {
|
||||
background: #1e88e5; /* Vibrant Blue */
|
||||
color: white;
|
||||
font-family: 'Zhi Mang Xing', cursive;
|
||||
font-size: 2.5em;
|
||||
border: none;
|
||||
border-radius: 50px;
|
||||
padding: 10px 30px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 5px 0 #1565c0; /* Darker Blue */
|
||||
transition: all 0.1s ease-in-out;
|
||||
}
|
||||
.theme-comic .new-joke-btn:active {
|
||||
transform: translateY(5px);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* --- Loading Animation --- */
|
||||
.loading-container { display: none; }
|
||||
.loading-container.visible { display: block; }
|
||||
.loading-anim {
|
||||
height: 60px;
|
||||
width: 80px;
|
||||
margin: 0 auto 10px;
|
||||
}
|
||||
.book {
|
||||
transform-style: preserve-3d;
|
||||
transform: rotateY(-30deg);
|
||||
animation: flip 3s infinite;
|
||||
}
|
||||
.book, .book-page {
|
||||
width: 40px;
|
||||
height: 55px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-left: -20px;
|
||||
margin-top: -27.5px;
|
||||
}
|
||||
.book-page {
|
||||
background: #ffca28;
|
||||
border: 1px solid #ff7043;
|
||||
border-radius: 3px;
|
||||
transform-origin: left;
|
||||
}
|
||||
.book-page:nth-child(1) { animation: flip-page 3s infinite; }
|
||||
.book-page:nth-child(2) { animation: flip-page 3s -1s infinite; }
|
||||
.book-page:nth-child(3) { animation: flip-page 3s -2s infinite; }
|
||||
|
||||
@keyframes flip { 50% { transform: rotateY(30deg); } }
|
||||
@keyframes flip-page { 30%, 100% { transform: rotateY(180deg); } }
|
||||
|
||||
/* --- Feedback Buttons & Animations --- */
|
||||
.feedback-buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.feedback-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 2em;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
.feedback-btn:hover { transform: scale(1.2); }
|
||||
|
||||
#animation-container {
|
||||
position: fixed;
|
||||
top: 0; left: 0; width: 100%; height: 100%;
|
||||
pointer-events: none; z-index: 999;
|
||||
}
|
||||
.confetti, .snowflake {
|
||||
position: absolute;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
.confetti {
|
||||
width: 10px; height: 10px;
|
||||
animation-name: fall;
|
||||
}
|
||||
.snowflake {
|
||||
font-size: 20px; color: #fff;
|
||||
animation-name: fall;
|
||||
}
|
||||
@keyframes fall {
|
||||
from { transform: translateY(-10vh) rotate(0deg); }
|
||||
to { transform: translateY(110vh) rotate(360deg); }
|
||||
}
|
||||
|
||||
.joke-card.absurd {
|
||||
animation: absurd-flash 0.5s 2;
|
||||
}
|
||||
@keyframes absurd-flash {
|
||||
0%, 100% { border: 2px solid transparent; }
|
||||
50% { border: 5px solid red; }
|
||||
}
|
||||
|
||||
/* --- General Joke Text Visibility --- */
|
||||
.joke-text {
|
||||
opacity: 0;
|
||||
transform: scale(0.9);
|
||||
transition: opacity 0.4s ease, transform 0.4s ease;
|
||||
}
|
||||
.joke-text.visible {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
/* --- Responsive --- */
|
||||
@media (max-width: 600px) {
|
||||
.theme-comic header h1 { font-size: 3em; }
|
||||
.theme-comic .joke-card { padding: 25px; transform: rotate(0); }
|
||||
.theme-comic .joke-card:hover { transform: rotate(0); }
|
||||
.theme-comic .joke-text { font-size: 1.5em; }
|
||||
}
|
||||
59
InfoGenie-frontend/public/60sapi/娱乐消遣/随机搞笑段子/index.html
Normal file
59
InfoGenie-frontend/public/60sapi/娱乐消遣/随机搞笑段子/index.html
Normal file
@@ -0,0 +1,59 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>段子游乐场</title>
|
||||
<link rel="stylesheet" href="css/background.css">
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
</head>
|
||||
<body class="theme-comic"> <!-- Default Theme -->
|
||||
|
||||
<div class="theme-switcher">
|
||||
<div class="theme-icon" data-theme="theme-comic" title="手绘漫画">✏️</div>
|
||||
<div class="theme-icon" data-theme="theme-emoji" title="表情包狂欢">😂</div>
|
||||
<div class="theme-icon" data-theme="theme-retro" title="复古电视">📺</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>段子游乐场</h1>
|
||||
<div class="divider"></div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div id="joke-card" class="joke-card">
|
||||
<div class="loading-container">
|
||||
<div class="loading-anim">
|
||||
<div class="book">
|
||||
<div class="book-page"></div>
|
||||
<div class="book-page"></div>
|
||||
<div class="book-page"></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>段子菌正在翻笑话库...</p>
|
||||
</div>
|
||||
<p id="joke-text" class="joke-text"></p>
|
||||
</div>
|
||||
|
||||
<div class="feedback-buttons">
|
||||
<button id="btn-lol" class="feedback-btn" title="笑到拍桌">🤣</button>
|
||||
<button id="btn-cold" class="feedback-btn" title="有点冷">🥶</button>
|
||||
<button id="btn-seen" class="feedback-btn" title="似曾相识">🤔</button>
|
||||
<button id="btn-absurd" class="feedback-btn" title="离谱但好笑">🤯</button>
|
||||
</div>
|
||||
|
||||
<button id="new-joke-btn" class="new-joke-btn">
|
||||
<span class="btn-text">再来一个!</span>
|
||||
</button>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- Animation & Sound Containers -->
|
||||
<div id="animation-container"></div>
|
||||
<audio id="sound-lol" src="https://www.myinstants.com/media/sounds/yay-6326.mp3" preload="auto"></audio>
|
||||
<audio id="sound-cold" src="https://www.myinstants.com/media/sounds/zapsplat_cartoon_whoosh_fast_swoosh_001_76761.mp3" preload="auto"></audio>
|
||||
|
||||
<script src="js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
122
InfoGenie-frontend/public/60sapi/娱乐消遣/随机搞笑段子/js/script.js
Normal file
122
InfoGenie-frontend/public/60sapi/娱乐消遣/随机搞笑段子/js/script.js
Normal file
@@ -0,0 +1,122 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Elements
|
||||
const body = document.body;
|
||||
const jokeTextElem = document.getElementById('joke-text');
|
||||
const newJokeBtn = document.getElementById('new-joke-btn');
|
||||
const loadingContainer = document.querySelector('.loading-container');
|
||||
const animationContainer = document.getElementById('animation-container');
|
||||
const jokeCard = document.getElementById('joke-card');
|
||||
|
||||
// API
|
||||
const apiBaseUrls = ["https://60s.api.shumengya.top"];
|
||||
const apiPath = "/v2/duanzi";
|
||||
let currentApiIndex = 0;
|
||||
|
||||
// --- Core Functions ---
|
||||
const showLoading = (isLoading) => {
|
||||
loadingContainer.classList.toggle('visible', isLoading);
|
||||
if (isLoading) jokeTextElem.classList.remove('visible');
|
||||
};
|
||||
|
||||
const displayJoke = (joke) => {
|
||||
jokeTextElem.textContent = joke;
|
||||
showLoading(false);
|
||||
setTimeout(() => jokeTextElem.classList.add('visible'), 50);
|
||||
};
|
||||
|
||||
const fetchJoke = async () => {
|
||||
showLoading(true);
|
||||
try {
|
||||
const url = apiBaseUrls[currentApiIndex] + apiPath;
|
||||
const response = await fetch(url, { timeout: 5000 });
|
||||
if (!response.ok) throw new Error('Network response was not ok');
|
||||
|
||||
const data = await response.json();
|
||||
if (data.code === 200 && data.data && data.data.duanzi) {
|
||||
displayJoke(data.data.duanzi);
|
||||
} else {
|
||||
throw new Error('Invalid data format');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`API error with ${apiBaseUrls[currentApiIndex]}:`, error);
|
||||
currentApiIndex = (currentApiIndex + 1) % apiBaseUrls.length;
|
||||
if (currentApiIndex !== 0) {
|
||||
fetchJoke(); // Try next API
|
||||
} else {
|
||||
displayJoke('段子菌迷路了!点击‘再来一个’让它重新找路~');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// --- Theme Switcher ---
|
||||
const themeSwitcher = document.querySelector('.theme-switcher');
|
||||
themeSwitcher.addEventListener('click', (e) => {
|
||||
if (e.target.classList.contains('theme-icon')) {
|
||||
const theme = e.target.dataset.theme;
|
||||
body.className = theme; // Set body class to the selected theme
|
||||
|
||||
// Update active icon
|
||||
themeSwitcher.querySelectorAll('.theme-icon').forEach(icon => icon.classList.remove('active'));
|
||||
e.target.classList.add('active');
|
||||
|
||||
alert(`主题已切换!部分主题(如表情包、复古电视)将在后续阶段实现。`);
|
||||
}
|
||||
});
|
||||
// Set initial active theme icon
|
||||
themeSwitcher.querySelector(`[data-theme="${body.className}"]`).classList.add('active');
|
||||
|
||||
|
||||
// --- Feedback Buttons & Animations ---
|
||||
const btnLol = document.getElementById('btn-lol');
|
||||
const btnCold = document.getElementById('btn-cold');
|
||||
const btnSeen = document.getElementById('btn-seen');
|
||||
const btnAbsurd = document.getElementById('btn-absurd');
|
||||
const soundLol = document.getElementById('sound-lol');
|
||||
const soundCold = document.getElementById('sound-cold');
|
||||
|
||||
btnLol.addEventListener('click', () => {
|
||||
soundLol.play();
|
||||
createParticles(20, 'confetti');
|
||||
});
|
||||
|
||||
btnCold.addEventListener('click', () => {
|
||||
soundCold.play();
|
||||
createParticles(15, 'snowflake');
|
||||
});
|
||||
|
||||
btnSeen.addEventListener('click', () => {
|
||||
displayJoke("原来你也听过!那再给你换个新鲜的~");
|
||||
setTimeout(fetchJoke, 1500);
|
||||
});
|
||||
|
||||
btnAbsurd.addEventListener('click', () => {
|
||||
jokeCard.classList.add('absurd');
|
||||
setTimeout(() => jokeCard.classList.remove('absurd'), 1000);
|
||||
});
|
||||
|
||||
function createParticles(count, type) {
|
||||
animationContainer.innerHTML = ''; // Clear previous
|
||||
const colors = ['#ffca28', '#ff7043', '#29b6f6', '#66bb6a'];
|
||||
for (let i = 0; i < count; i++) {
|
||||
const particle = document.createElement('div');
|
||||
particle.classList.add(type);
|
||||
if (type === 'confetti') {
|
||||
particle.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
|
||||
} else {
|
||||
particle.textContent = '❄️';
|
||||
}
|
||||
particle.style.left = `${Math.random() * 100}vw`;
|
||||
const duration = Math.random() * 3 + 2; // 2-5 seconds
|
||||
const delay = Math.random() * -duration; // Start at different times
|
||||
particle.style.animationDuration = `${duration}s`;
|
||||
particle.style.animationDelay = `${delay}s`;
|
||||
animationContainer.appendChild(particle);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Event Listeners ---
|
||||
newJokeBtn.addEventListener('click', fetchJoke);
|
||||
|
||||
// --- Initial Load ---
|
||||
fetchJoke();
|
||||
});
|
||||
1
InfoGenie-frontend/public/60sapi/娱乐消遣/随机搞笑段子/接口集合.json
Normal file
1
InfoGenie-frontend/public/60sapi/娱乐消遣/随机搞笑段子/接口集合.json
Normal file
@@ -0,0 +1 @@
|
||||
["https://60s.api.shumengya.top"]
|
||||
8
InfoGenie-frontend/public/60sapi/娱乐消遣/随机搞笑段子/返回接口.json
Normal file
8
InfoGenie-frontend/public/60sapi/娱乐消遣/随机搞笑段子/返回接口.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841",
|
||||
"data": {
|
||||
"index": 347,
|
||||
"duanzi": "我不想读书,主要是因为家里牛啊,猪啊羊啊都没人喂。"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
body {
|
||||
background: linear-gradient(-45deg, #0a021a, #2a0d3f, #4a1a6c, #7b2f8f);
|
||||
background-size: 400% 400%;
|
||||
animation: gradientBG 20s ease infinite;
|
||||
color: #ffffff;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
@keyframes gradientBG {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
342
InfoGenie-frontend/public/60sapi/娱乐消遣/随机运势/css/style.css
Normal file
342
InfoGenie-frontend/public/60sapi/娱乐消遣/随机运势/css/style.css
Normal file
@@ -0,0 +1,342 @@
|
||||
.container {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
header h1 {
|
||||
font-size: 2.8em;
|
||||
color: #f0e6ff;
|
||||
text-shadow: 0 0 10px #d1a9ff, 0 0 20px #d1a9ff;
|
||||
margin-bottom: 0.2em;
|
||||
}
|
||||
|
||||
header p {
|
||||
font-size: 1.2em;
|
||||
color: #e0c8ff;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.crystal-ball-container {
|
||||
perspective: 1000px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.crystal-ball {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background: radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0.6), rgba(200, 180, 255, 0.1));
|
||||
border-radius: 50%;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
box-shadow: 0 0 30px #c390ff, 0 0 60px #a060e0, inset 0 0 20px rgba(255, 220, 255, 0.3);
|
||||
animation: float 6s ease-in-out infinite;
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
.reflection {
|
||||
width: 80px;
|
||||
height: 40px;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 40px;
|
||||
transform: rotate(-30deg);
|
||||
filter: blur(5px);
|
||||
}
|
||||
|
||||
.swirl {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 120%;
|
||||
height: 120%;
|
||||
background: linear-gradient(45deg, rgba(255, 192, 203, 0.1), rgba(128, 0, 128, 0.2));
|
||||
border-radius: 50%;
|
||||
animation: swirl 10s linear infinite;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-20px); }
|
||||
}
|
||||
|
||||
@keyframes swirl {
|
||||
from { transform: translate(-50%, -50%) rotate(0deg); }
|
||||
to { transform: translate(-50%, -50%) rotate(360deg); }
|
||||
}
|
||||
|
||||
.fortune-card {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 15px;
|
||||
padding: 30px;
|
||||
margin-bottom: 30px;
|
||||
min-height: 120px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
|
||||
transition: opacity 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
.fortune-content {
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
.fortune-content.visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#luck-desc {
|
||||
font-size: 2em;
|
||||
color: #ffc0cb;
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
#luck-tip {
|
||||
font-size: 1.1em;
|
||||
color: #e0e0e0;
|
||||
margin: 0;
|
||||
padding-bottom: 20px; /* Add some space before the new details */
|
||||
}
|
||||
|
||||
.fortune-details {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-top: 20px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.detail-item h3 {
|
||||
font-size: 0.9em;
|
||||
color: #ffc0cb;
|
||||
margin: 0 0 5px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.detail-item p {
|
||||
font-size: 1.2em;
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#lucky-color {
|
||||
display: inline-block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid white;
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
|
||||
/* Remove the text content */
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
/* Tarot Card Styles */
|
||||
.tarot-container {
|
||||
margin-top: 40px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.tarot-container h2 {
|
||||
font-size: 1.5em;
|
||||
color: #f0e6ff;
|
||||
text-shadow: 0 0 8px #d1a9ff;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.tarot-card-container {
|
||||
width: 180px;
|
||||
height: 280px;
|
||||
perspective: 1000px;
|
||||
margin: 0 auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tarot-card-inner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: transform 0.8s;
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
.tarot-card-container.flipped .tarot-card-inner {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
.tarot-card-front,
|
||||
.tarot-card-back {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.tarot-card-back {
|
||||
background: linear-gradient(135deg, #4a1a6c, #2a0d3f);
|
||||
border: 2px solid #d1a9ff;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 3em;
|
||||
color: #d1a9ff;
|
||||
}
|
||||
|
||||
.tarot-card-back::after {
|
||||
content: '✧'; /* A simple star symbol */
|
||||
text-shadow: 0 0 10px #f0e6ff;
|
||||
}
|
||||
|
||||
.tarot-card-front {
|
||||
background: linear-gradient(135deg, #3e165b, #592883);
|
||||
border: 2px solid #d1a9ff;
|
||||
color: white;
|
||||
transform: rotateY(180deg);
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#tarot-name {
|
||||
font-size: 1.4em;
|
||||
color: #ffc0cb;
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
#tarot-interpretation {
|
||||
font-size: 0.9em;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Side Decorations */
|
||||
.side-decor {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 15vw;
|
||||
height: 100vh;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.left-decor {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.right-decor {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.decor-symbol {
|
||||
position: absolute;
|
||||
color: rgba(209, 169, 255, 0.5);
|
||||
text-shadow: 0 0 10px rgba(240, 230, 255, 0.7);
|
||||
animation: floatSymbol 20s infinite ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes floatSymbol {
|
||||
0%, 100% {
|
||||
transform: translateY(0) rotate(0deg);
|
||||
opacity: 0;
|
||||
}
|
||||
25%, 75% {
|
||||
opacity: 0.8;
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-20vh) rotate(180deg);
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
|
||||
#get-fortune-btn {
|
||||
background: linear-gradient(45deg, #da70d6, #8a2be2);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50px;
|
||||
padding: 15px 30px;
|
||||
font-size: 1.1em;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
box-shadow: 0 0 15px #c390ff;
|
||||
}
|
||||
|
||||
#get-fortune-btn:hover {
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 0 25px #d1a9ff;
|
||||
}
|
||||
|
||||
#get-fortune-btn:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
border: 4px solid rgba(255, 255, 255, 0.2);
|
||||
border-left-color: #ffc0cb;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
animation: spin 1s linear infinite;
|
||||
display: none; /* Hidden by default */
|
||||
}
|
||||
|
||||
.loading-spinner.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-top: 40px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
header h1 {
|
||||
font-size: 2.2em;
|
||||
}
|
||||
.crystal-ball {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.fortune-card {
|
||||
padding: 20px;
|
||||
}
|
||||
.fortune-details {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.tarot-card-container {
|
||||
width: 150px;
|
||||
height: 233px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide side decor on smaller screens */
|
||||
@media (max-width: 1200px) {
|
||||
.side-decor {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
71
InfoGenie-frontend/public/60sapi/娱乐消遣/随机运势/index.html
Normal file
71
InfoGenie-frontend/public/60sapi/娱乐消遣/随机运势/index.html
Normal file
@@ -0,0 +1,71 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>水晶球占卜</title>
|
||||
<link rel="stylesheet" href="css/background.css">
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="side-decor left-decor"></div>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>水晶球占卜</h1>
|
||||
<p>洞察你今日的运势</p>
|
||||
</header>
|
||||
<main>
|
||||
<div class="crystal-ball-container">
|
||||
<div class="crystal-ball">
|
||||
<div class="reflection"></div>
|
||||
<div class="swirl"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="fortune-card" class="fortune-card">
|
||||
<div class="loading-spinner"></div>
|
||||
<div class="fortune-content">
|
||||
<h2 id="luck-desc"></h2>
|
||||
<p id="luck-tip"></p>
|
||||
<div class="fortune-details">
|
||||
<div class="detail-item">
|
||||
<h3>今日咒语</h3>
|
||||
<p id="fortune-summary"></p>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<h3>幸运色</h3>
|
||||
<p id="lucky-color"></p>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<h3>幸运数字</h3>
|
||||
<p id="lucky-number"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- New Tarot Card Section -->
|
||||
<div class="tarot-container">
|
||||
<h2>每日塔罗指引</h2>
|
||||
<div id="tarot-card" class="tarot-card-container">
|
||||
<div class="tarot-card-inner">
|
||||
<div class="tarot-card-back">
|
||||
<!-- Back of the card design -->
|
||||
</div>
|
||||
<div class="tarot-card-front">
|
||||
<h3 id="tarot-name"></h3>
|
||||
<p id="tarot-interpretation"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="get-fortune-btn">再次占卜</button>
|
||||
</main>
|
||||
<footer>
|
||||
<p>仅供娱乐,祝您好运</p>
|
||||
</footer>
|
||||
</div>
|
||||
<div class="side-decor right-decor"></div>
|
||||
<script src="js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
170
InfoGenie-frontend/public/60sapi/娱乐消遣/随机运势/js/script.js
Normal file
170
InfoGenie-frontend/public/60sapi/娱乐消遣/随机运势/js/script.js
Normal file
@@ -0,0 +1,170 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const getFortuneBtn = document.getElementById('get-fortune-btn');
|
||||
const fortuneCard = document.getElementById('fortune-card');
|
||||
const fortuneContent = fortuneCard.querySelector('.fortune-content');
|
||||
const luckDescElem = document.getElementById('luck-desc');
|
||||
const luckTipElem = document.getElementById('luck-tip');
|
||||
const fortuneSummaryElem = document.getElementById('fortune-summary');
|
||||
const luckyColorElem = document.getElementById('lucky-color');
|
||||
const luckyNumberElem = document.getElementById('lucky-number');
|
||||
const loadingSpinner = fortuneCard.querySelector('.loading-spinner');
|
||||
const tarotCardContainer = document.getElementById('tarot-card');
|
||||
const tarotNameElem = document.getElementById('tarot-name');
|
||||
const tarotInterpretationElem = document.getElementById('tarot-interpretation');
|
||||
|
||||
const apiBaseUrls = [
|
||||
"https://60s.api.shumengya.top",
|
||||
];
|
||||
const apiPath = "/v2/luck";
|
||||
|
||||
const mantras = [
|
||||
"顺其自然,皆是美好。",
|
||||
"相信直觉,它知道方向。",
|
||||
"每一次呼吸都是新的开始。",
|
||||
"心怀感恩,好运自来。",
|
||||
"拥抱变化,发现惊喜。",
|
||||
"你的能量,超乎想象。",
|
||||
"保持微笑,宇宙会回应你。"
|
||||
];
|
||||
|
||||
const tarotDeck = [
|
||||
{ name: "愚者", interpretation: "新的开始,无限的潜力,天真和自由。勇敢地迈出第一步。" },
|
||||
{ name: "魔术师", interpretation: "创造力,意志力,显化。你拥有实现目标所需的一切资源。" },
|
||||
{ name: "女祭司", interpretation: "直觉,潜意识,神秘。倾听你内心的声音,智慧在你之内。" },
|
||||
{ name: "皇后", interpretation: "丰饶,母性,创造。享受生活的美好,与自然和谐相处。" },
|
||||
{ name: "皇帝", interpretation: "权威,结构,控制。建立秩序和纪律,掌控你的生活。" },
|
||||
{ name: "教皇", interpretation: "传统,信仰,灵性指导。寻求智慧和知识,遵循传统。" },
|
||||
{ name: "恋人", interpretation: "爱,和谐,选择。做出与你内心价值观一致的决定。" },
|
||||
{ name: "战车", interpretation: "胜利,决心,控制。以坚定的意志力克服障碍,勇往直前。" },
|
||||
{ name: "力量", interpretation: "勇气,内在力量,同情。用温柔和耐心驯服内心的野兽。" },
|
||||
{ name: "隐士", interpretation: "内省,孤独,寻求真理。花时间独处,向内寻求答案。" },
|
||||
{ name: "命运之轮", interpretation: "变化,命运,转折点。生活总在变化,顺应潮流。" },
|
||||
{ name: "正义", interpretation: "公平,真理,因果。为你的行为负责,寻求平衡。" },
|
||||
{ name: "倒吊人", interpretation: "新的视角,顺从,牺牲。放手,从不同的角度看问题。" },
|
||||
{ name: "死神", interpretation: "结束,转变,新生。一个周期的结束是另一个周期的开始。" },
|
||||
{ name: "节制", interpretation: "平衡,和谐,耐心。融合对立的力量,找到中间道路。" },
|
||||
{ name: "恶魔", interpretation: "束缚,物质主义,诱惑。认识到你的束缚,并寻求解放。" },
|
||||
{ name: "塔", interpretation: "突变,启示,解放。旧的结构正在崩塌,为新的结构让路。" },
|
||||
{ name: "星星", interpretation: "希望,灵感,平静。在黑暗之后,总有希望的曙光。" },
|
||||
{ name: "月亮", interpretation: "幻觉,恐惧,潜意识。面对你的恐惧,相信你的直觉。" },
|
||||
{ name: "太阳", interpretation: "成功,喜悦,活力。拥抱光明,享受生活的乐趣。" },
|
||||
{ name: "审判", interpretation: "觉醒,重生,评估。一个反思和更新的时刻。" },
|
||||
{ name: "世界", interpretation: "完成,整合,成就。一个旅程的成功结束,庆祝你的成就。" }
|
||||
];
|
||||
|
||||
let currentApiIndex = 0;
|
||||
|
||||
const showLoading = (isLoading) => {
|
||||
if (isLoading) {
|
||||
fortuneContent.classList.remove('visible');
|
||||
loadingSpinner.classList.add('visible');
|
||||
} else {
|
||||
loadingSpinner.classList.remove('visible');
|
||||
setTimeout(() => {
|
||||
fortuneContent.classList.add('visible');
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchFortune = async () => {
|
||||
showLoading(true);
|
||||
tarotCardContainer.classList.remove('flipped'); // Reset card on new fetch
|
||||
|
||||
try {
|
||||
const url = apiBaseUrls[currentApiIndex] + apiPath;
|
||||
const response = await fetch(url, { timeout: 5000 });
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
const data = await response.json();
|
||||
|
||||
if (data.code === 200 && data.data) {
|
||||
updateFortune(data.data);
|
||||
drawTarotCard(); // Draw a tarot card on success
|
||||
} else {
|
||||
throw new Error('Invalid data format');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`API error with ${apiBaseUrls[currentApiIndex]}:`, error);
|
||||
currentApiIndex = (currentApiIndex + 1) % apiBaseUrls.length;
|
||||
if (currentApiIndex !== 0) {
|
||||
fetchFortune(); // Try next API
|
||||
} else {
|
||||
displayError();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const updateFortune = (data) => {
|
||||
luckDescElem.textContent = data.luck_desc || '运势';
|
||||
luckTipElem.textContent = data.luck_tip || '今日运势平平,保持好心情。';
|
||||
|
||||
// Generate and display additional details
|
||||
fortuneSummaryElem.textContent = mantras[Math.floor(Math.random() * mantras.length)];
|
||||
luckyColorElem.style.backgroundColor = `#${Math.floor(Math.random()*16777215).toString(16).padStart(6, '0')}`;
|
||||
luckyNumberElem.textContent = Math.floor(Math.random() * 100);
|
||||
|
||||
showLoading(false);
|
||||
};
|
||||
|
||||
const displayError = () => {
|
||||
luckDescElem.textContent = '占卜失败';
|
||||
luckTipElem.textContent = '无法连接到星辰之力,请稍后再试。';
|
||||
fortuneSummaryElem.textContent = '---';
|
||||
luckyColorElem.style.backgroundColor = 'transparent';
|
||||
luckyNumberElem.textContent = '-';
|
||||
showLoading(false);
|
||||
tarotNameElem.textContent = '指引中断';
|
||||
tarotInterpretationElem.textContent = '星辰之力暂时无法连接。';
|
||||
tarotCardContainer.classList.add('flipped'); // Show error on card
|
||||
};
|
||||
|
||||
const drawTarotCard = () => {
|
||||
const card = tarotDeck[Math.floor(Math.random() * tarotDeck.length)];
|
||||
tarotNameElem.textContent = card.name;
|
||||
tarotInterpretationElem.textContent = card.interpretation;
|
||||
|
||||
// Flip the card after a short delay to allow the main content to appear
|
||||
setTimeout(() => {
|
||||
tarotCardContainer.classList.add('flipped');
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const createSideDecorations = () => {
|
||||
const leftContainer = document.querySelector('.left-decor');
|
||||
const rightContainer = document.querySelector('.right-decor');
|
||||
if (!leftContainer || !rightContainer) return;
|
||||
|
||||
const symbols = ['✧', '✦', '☾', '✶', '✵', '✩', '✨'];
|
||||
const symbolCount = 15; // Number of symbols per side
|
||||
|
||||
const createSymbols = (container) => {
|
||||
for (let i = 0; i < symbolCount; i++) {
|
||||
const symbol = document.createElement('span');
|
||||
symbol.classList.add('decor-symbol');
|
||||
symbol.textContent = symbols[Math.floor(Math.random() * symbols.length)];
|
||||
|
||||
// Randomize properties for a more natural look
|
||||
symbol.style.top = `${Math.random() * 90}vh`;
|
||||
symbol.style.left = `${Math.random() * 80}%`;
|
||||
symbol.style.fontSize = `${Math.random() * 20 + 10}px`;
|
||||
symbol.style.animationDelay = `${Math.random() * 20}s`;
|
||||
symbol.style.animationDuration = `${Math.random() * 20 + 15}s`; // Duration between 15s and 35s
|
||||
|
||||
container.appendChild(symbol);
|
||||
}
|
||||
};
|
||||
|
||||
createSymbols(leftContainer);
|
||||
createSymbols(rightContainer);
|
||||
};
|
||||
|
||||
getFortuneBtn.addEventListener('click', fetchFortune);
|
||||
tarotCardContainer.addEventListener('click', () => {
|
||||
tarotCardContainer.classList.toggle('flipped');
|
||||
});
|
||||
|
||||
// Initial actions on page load
|
||||
fetchFortune();
|
||||
createSideDecorations();
|
||||
});
|
||||
3
InfoGenie-frontend/public/60sapi/娱乐消遣/随机运势/接口集合.json
Normal file
3
InfoGenie-frontend/public/60sapi/娱乐消遣/随机运势/接口集合.json
Normal file
@@ -0,0 +1,3 @@
|
||||
[
|
||||
"https://60s.api.shumengya.top"
|
||||
]
|
||||
10
InfoGenie-frontend/public/60sapi/娱乐消遣/随机运势/返回接口.json
Normal file
10
InfoGenie-frontend/public/60sapi/娱乐消遣/随机运势/返回接口.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841",
|
||||
"data": {
|
||||
"luck_desc": "恋愛運",
|
||||
"luck_rank": 21,
|
||||
"luck_tip": "闪亮的邂逅之日!顺其自然吧",
|
||||
"luck_tip_index": 19
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user