Files
aitsc/src/flask_prompt_master/templates/apikey_apply.html
renjianbo 6f80d7f4c0 feat: add consistent footer navigation across all pages
- Footer on homepage, API docs, and application pages
- Two groups: 专家工具 + API 服务
- Cleaned up homepage header to show only 5号/6号 experts
- Responsive layout for mobile

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-28 00:31:05 +08:00

314 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}申请 API Key — 提示词优化服务{% endblock %}
{% block content %}
<div class="layout">
<div class="card">
<div class="card-header">
<h1><i class="fas fa-key"></i> 申请 API Key</h1>
<p>免费申请,即时生效。用于调用提示词优化接口。</p>
</div>
<div class="steps">
<div class="step done">
<div class="step-num">1</div>
<span>填写信息</span>
</div>
<div class="step-connector" id="conn1"></div>
<div class="step" id="step2">
<div class="step-num">2</div>
<span>获取密钥</span>
</div>
<div class="step-connector" id="conn2"></div>
<div class="step" id="step3">
<div class="step-num">3</div>
<span>开始调用</span>
</div>
</div>
<div id="formArea">
<form id="applyForm">
<div class="form-group">
<label for="name">名称 <span class="required">*</span></label>
<input type="text" id="name" placeholder="例如:张三" required>
</div>
<div class="form-group">
<label for="email">邮箱 <span class="optional">(选填)</span></label>
<input type="email" id="email" placeholder="用于接收服务通知">
</div>
<button type="submit" id="submitBtn">
<i class="fas fa-bolt"></i> 立即申请
</button>
</form>
</div>
<div id="resultArea" style="display:none;">
<div class="result-box">
<h3><i class="fas fa-check-circle"></i> 申请成功</h3>
<p class="warn">此密钥仅展示一次,请立即复制保存</p>
<div class="key-display" id="keyDisplay"></div>
<button class="btn-copy" id="copyKeyBtn">
<i class="fas fa-copy"></i> 复制密钥
</button>
<div class="next-section">
<h4>如何使用</h4>
<pre class="code-block"><code>curl -X POST {{ request.host_url }}api/v1/prompt/optimize \
-H "Content-Type: application/json" \
-H "X-API-Key: <span class="placeholder">你的密钥</span>" \
-d "{\"input_text\": \"写一个Python数据分析脚本\"}"</code></pre>
<p class="next-link">详细文档 → <a href="/api-docs">/api-docs</a></p>
</div>
</div>
</div>
<div class="site-footer">
<div class="footer-group">
<span class="footer-label">专家工具</span>
<a href="/">AI 提示词生成器</a>
<a href="/expert-generate-6">6号专家纯提示词</a>
<a href="/expert-generate-5">5号专家含样例</a>
</div>
<div class="footer-divider"></div>
<div class="footer-group">
<span class="footer-label">API 服务</span>
<a href="/api-docs">API 文档</a>
<a href="/api-key/apply">申请 API Key</a>
<a href="/admin/apikeys">管理 API Key</a>
</div>
</div>
</div>
</div>
<div class="toast-container" id="toastContainer"></div>
{% endblock %}
{% block extra_css %}
<style>
.layout {
min-height: calc(100vh - 120px);
padding: 3rem 1.5rem;
background: linear-gradient(135deg, #f0fdfa 0%, #ecfeff 100%);
display: flex;
justify-content: center;
}
.card {
width: 100%;
max-width: 560px;
background: white;
border-radius: 16px;
padding: 2.5rem 2rem;
box-shadow: 0 4px 24px rgba(0,0,0,0.08);
height: fit-content;
}
.card-header { text-align: center; margin-bottom: 2rem; }
.card-header h1 {
font-size: 1.6rem; font-weight: 700;
display: flex; align-items: center; justify-content: center; gap: 0.5rem;
}
.card-header h1 i { color: #06b6d4; }
.card-header p { color: var(--text-light); margin-top: 0.25rem; font-size: 0.9rem; }
/* Steps */
.steps {
display: flex; align-items: center; justify-content: center;
margin-bottom: 2rem; gap: 0;
}
.step {
display: flex; flex-direction: column; align-items: center; gap: 0.35rem;
opacity: 0.4; transition: opacity 0.5s;
}
.step.done, .step.current { opacity: 1; }
.step-num {
width: 32px; height: 32px; border-radius: 50%;
background: #e2e8f0; color: var(--text-secondary);
display: flex; align-items: center; justify-content: center;
font-weight: 700; font-size: 0.85rem; transition: all 0.5s;
}
.step.done .step-num { background: #06b6d4; color: white; }
.step.current .step-num { background: #06b6d4; color: white; box-shadow: 0 0 0 4px rgba(6,182,212,0.2); }
.step span { font-size: 0.78rem; color: var(--text-secondary); font-weight: 500; }
.step.done span, .step.current span { color: var(--text-color); }
.step-connector {
width: 40px; height: 2px; background: #e2e8f0;
margin: 0 0.25rem; transition: background 0.5s;
}
.step-connector.done { background: #06b6d4; }
/* Form */
.form-group { margin-bottom: 1.25rem; }
.form-group label {
display: block; font-weight: 600; font-size: 0.85rem;
margin-bottom: 0.4rem; color: var(--text-color);
}
.required { color: #ef4444; }
.optional { color: var(--text-muted); font-weight: 400; font-size: 0.78rem; }
.form-group input {
width: 100%; padding: 0.7rem 0.85rem;
border: 2px solid var(--border-color); border-radius: 10px;
font-size: 0.95rem; transition: border-color 0.2s;
}
.form-group input:focus {
outline: none; border-color: #06b6d4;
box-shadow: 0 0 0 3px rgba(6,182,212,0.1);
}
button[type="submit"] {
width: 100%; padding: 0.8rem;
background: linear-gradient(135deg, #06b6d4, #3b82f6);
color: white; border: none; border-radius: 10px;
font-size: 1rem; font-weight: 600; cursor: pointer;
transition: all 0.2s; display: flex; align-items: center;
justify-content: center; gap: 0.5rem;
}
button[type="submit"]:hover { transform: translateY(-1px); box-shadow: 0 4px 16px rgba(6,182,212,0.3); }
button[type="submit"]:disabled { opacity: 0.6; cursor: not-allowed; transform: none; }
/* Result */
.result-box {
text-align: center;
}
.result-box h3 {
font-size: 1.2rem; margin: 0 0 0.5rem 0;
display: flex; align-items: center; justify-content: center; gap: 0.5rem;
}
.result-box h3 i { color: #10b981; }
.warn {
color: #f59e0b; font-weight: 500; font-size: 0.85rem; margin: 0 0 1rem 0;
}
.key-display {
background: #1e293b; color: #10b981; border-radius: 10px;
padding: 1rem; font-family: 'SF Mono', 'Monaco', monospace;
font-size: 0.95rem; word-break: break-all; margin-bottom: 0.75rem;
}
.btn-copy {
display: inline-flex; align-items: center; gap: 0.4rem;
padding: 0.55rem 1.25rem; border-radius: 8px; border: none;
background: #10b981; color: white; font-weight: 600; cursor: pointer;
font-size: 0.9rem; margin-bottom: 2rem;
transition: transform 0.2s;
}
.btn-copy:hover { transform: translateY(-1px); }
.next-section {
text-align: left;
background: #f8fafc; border-radius: 10px; padding: 1.25rem;
}
.next-section h4 { font-size: 0.9rem; margin: 0 0 0.75rem 0; }
.code-block {
background: #1e293b; color: #e2e8f0; border-radius: 8px;
padding: 0.75rem 1rem; font-family: 'SF Mono', 'Monaco', monospace;
font-size: 0.8rem; line-height: 1.6; overflow-x: auto;
white-space: pre; margin-bottom: 0.75rem;
}
.code-block .placeholder { color: #f59e0b; }
.next-link { font-size: 0.85rem; color: var(--text-light); margin: 0; }
.next-link a { color: #06b6d4; font-weight: 500; }
/* Toast */
.toast-container { position: fixed; top: 1rem; right: 1rem; z-index: 9999; display: flex; flex-direction: column; gap: 0.5rem; }
.toast { padding: 0.75rem 1.25rem; border-radius: 8px; color: white; font-size: 0.875rem; font-weight: 500; animation: slideIn 0.3s ease; }
.toast.error { background: #ef4444; }
.toast.success { background: #10b981; }
@keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
/* Footer nav */
.site-footer {
display: flex; justify-content: center; align-items: flex-start;
gap: 2rem; margin-top: 3rem; padding-top: 1.5rem;
border-top: 1px solid var(--border-color);
}
.footer-group { display: flex; flex-direction: column; gap: 0.35rem; }
.footer-label { font-size: 0.72rem; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 0.25rem; }
.footer-group a { font-size: 0.85rem; color: var(--text-secondary); text-decoration: none; transition: color 0.2s; }
.footer-group a:hover { color: #06b6d4; }
.footer-divider { width: 1px; background: var(--border-color); align-self: stretch; }
@media (max-width: 768px) {
.layout { padding: 1.5rem 1rem; }
.card { padding: 1.5rem 1.25rem; }
.site-footer { flex-direction: column; gap: 1rem; }
.footer-divider { width: auto; height: 1px; }
}
</style>
{% endblock %}
{% block scripts %}
<script>
(function() {
var form = document.getElementById('applyForm');
var formArea = document.getElementById('formArea');
var resultArea = document.getElementById('resultArea');
var submitBtn = document.getElementById('submitBtn');
var step2 = document.getElementById('step2');
var step3 = document.getElementById('step3');
var conn1 = document.getElementById('conn1');
var conn2 = document.getElementById('conn2');
function showToast(msg, type) {
var c = document.getElementById('toastContainer');
var t = document.createElement('div');
t.className = 'toast ' + type;
t.textContent = msg;
c.appendChild(t);
setTimeout(function() {
t.style.opacity = '0'; t.style.transition = 'all 0.3s ease';
setTimeout(function() { t.remove(); }, 300);
}, 3000);
}
form.addEventListener('submit', function(e) {
e.preventDefault();
var name = document.getElementById('name').value.trim();
var email = document.getElementById('email').value.trim();
if (!name) { showToast('请填写名称', 'error'); return; }
submitBtn.disabled = true;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 申请中...';
fetch('/api/api-key/apply', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: name, email: email })
})
.then(function(r) { return r.json(); })
.then(function(data) {
submitBtn.disabled = false;
submitBtn.innerHTML = '<i class="fas fa-bolt"></i> 立即申请';
if (data.code === 200) {
document.getElementById('keyDisplay').textContent = data.data.key;
formArea.style.display = 'none';
resultArea.style.display = '';
step2.classList.add('done');
step3.classList.add('current');
conn1.classList.add('done');
conn2.classList.add('done');
} else {
showToast(data.message || '申请失败', 'error');
}
})
.catch(function() {
submitBtn.disabled = false;
submitBtn.innerHTML = '<i class="fas fa-bolt"></i> 立即申请';
showToast('网络请求失败', 'error');
});
});
document.getElementById('copyKeyBtn').addEventListener('click', function() {
var key = document.getElementById('keyDisplay').textContent;
navigator.clipboard.writeText(key).then(function() {
showToast('已复制到剪贴板', 'success');
}).catch(function() {
showToast('复制失败,请手动选择', 'error');
});
});
})();
</script>
{% endblock %}