366 lines
9.1 KiB
HTML
366 lines
9.1 KiB
HTML
|
|
{% extends "base.html" %}
|
||
|
|
|
||
|
|
{% block content %}
|
||
|
|
<div class="container">
|
||
|
|
<!-- 页面标题区域 -->
|
||
|
|
<div class="page-header">
|
||
|
|
<h1>提示词模板库</h1>
|
||
|
|
<p class="subtitle">选择适合您需求的专业模板</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- 分类导航 -->
|
||
|
|
<div class="category-nav">
|
||
|
|
<div class="category-item {% if current_category == '全部' %}active{% endif %}">
|
||
|
|
<i class="fas fa-th-large"></i>
|
||
|
|
<a href="{{ url_for('prompts.list', category='全部') }}">全部模板</a>
|
||
|
|
</div>
|
||
|
|
{% for category, info in categories.items() %}
|
||
|
|
<div class="category-item {% if current_category == category %}active{% endif %}">
|
||
|
|
<i class="{{ info.icon }}"></i>
|
||
|
|
<a href="{{ url_for('prompts.list', category=category) }}">
|
||
|
|
{{ category }}
|
||
|
|
<span class="template-count">{{ info.templates|length }}</span>
|
||
|
|
</a>
|
||
|
|
</div>
|
||
|
|
{% endfor %}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- 搜索和筛选区域 -->
|
||
|
|
<div class="filter-section">
|
||
|
|
<div class="search-box">
|
||
|
|
<i class="fas fa-search"></i>
|
||
|
|
<input type="text" placeholder="搜索模板..." id="templateSearch">
|
||
|
|
</div>
|
||
|
|
<div class="view-toggle">
|
||
|
|
<button class="view-btn active" data-view="grid">
|
||
|
|
<i class="fas fa-th-large"></i>
|
||
|
|
</button>
|
||
|
|
<button class="view-btn" data-view="list">
|
||
|
|
<i class="fas fa-list"></i>
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- 模板列表 -->
|
||
|
|
<div class="template-grid" id="templateContainer">
|
||
|
|
{% for template in templates %}
|
||
|
|
<div class="template-card" data-category="{{ template.category }}">
|
||
|
|
<div class="card-header">
|
||
|
|
<i class="{{ categories[template.category].icon if template.category in categories }}"></i>
|
||
|
|
<h3>{{ template.name }}</h3>
|
||
|
|
</div>
|
||
|
|
<div class="card-body">
|
||
|
|
<p class="description">{{ template.description }}</p>
|
||
|
|
<div class="tags">
|
||
|
|
<span class="tag industry">
|
||
|
|
<i class="fas fa-building"></i>
|
||
|
|
{{ template.industry }}
|
||
|
|
</span>
|
||
|
|
<span class="tag profession">
|
||
|
|
<i class="fas fa-user-tie"></i>
|
||
|
|
{{ template.profession }}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="card-footer">
|
||
|
|
<button class="btn-preview" onclick="previewTemplate('{{ template.id }}')">
|
||
|
|
<i class="fas fa-eye"></i> 预览
|
||
|
|
</button>
|
||
|
|
<button class="btn-use" onclick="useTemplate('{{ template.id }}')">
|
||
|
|
<i class="fas fa-plus"></i> 使用模板
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
{% endfor %}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- 分页控件 -->
|
||
|
|
<div class="pagination">
|
||
|
|
{% if page > 1 %}
|
||
|
|
<a href="{{ url_for('prompts.list', page=page-1, category=current_category) }}" class="page-btn">
|
||
|
|
<i class="fas fa-chevron-left"></i> 上一页
|
||
|
|
</a>
|
||
|
|
{% endif %}
|
||
|
|
|
||
|
|
<div class="page-numbers">
|
||
|
|
{% for p in range(1, total_pages + 1) %}
|
||
|
|
<a href="{{ url_for('prompts.list', page=p, category=current_category) }}"
|
||
|
|
class="page-number {% if p == page %}active{% endif %}">
|
||
|
|
{{ p }}
|
||
|
|
</a>
|
||
|
|
{% endfor %}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{% if has_next %}
|
||
|
|
<a href="{{ url_for('prompts.list', page=page+1, category=current_category) }}" class="page-btn">
|
||
|
|
下一页 <i class="fas fa-chevron-right"></i>
|
||
|
|
</a>
|
||
|
|
{% endif %}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- 模板预览模态框 -->
|
||
|
|
<div class="modal" id="previewModal">
|
||
|
|
<div class="modal-content">
|
||
|
|
<span class="close">×</span>
|
||
|
|
<div class="modal-body"></div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
{% endblock %}
|
||
|
|
|
||
|
|
{% block styles %}
|
||
|
|
<style>
|
||
|
|
:root {
|
||
|
|
--primary-color: #2563eb;
|
||
|
|
--secondary-color: #3b82f6;
|
||
|
|
--background-color: #f8fafc;
|
||
|
|
--text-color: #1e293b;
|
||
|
|
--border-color: #e2e8f0;
|
||
|
|
--hover-color: #dbeafe;
|
||
|
|
--shadow-color: rgba(0, 0, 0, 0.1);
|
||
|
|
}
|
||
|
|
|
||
|
|
.container {
|
||
|
|
max-width: 1200px;
|
||
|
|
margin: 0 auto;
|
||
|
|
padding: 2rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.page-header {
|
||
|
|
text-align: center;
|
||
|
|
margin-bottom: 3rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.page-header h1 {
|
||
|
|
font-size: 2.5rem;
|
||
|
|
color: var(--text-color);
|
||
|
|
margin-bottom: 0.5rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.subtitle {
|
||
|
|
color: #64748b;
|
||
|
|
font-size: 1.1rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.category-nav {
|
||
|
|
display: flex;
|
||
|
|
gap: 1rem;
|
||
|
|
margin-bottom: 2rem;
|
||
|
|
overflow-x: auto;
|
||
|
|
padding: 1rem;
|
||
|
|
scrollbar-width: thin;
|
||
|
|
-webkit-overflow-scrolling: touch;
|
||
|
|
}
|
||
|
|
|
||
|
|
.category-item {
|
||
|
|
padding: 0.75rem 1.25rem;
|
||
|
|
border-radius: 999px;
|
||
|
|
background: white;
|
||
|
|
box-shadow: 0 1px 3px var(--shadow-color);
|
||
|
|
cursor: pointer;
|
||
|
|
transition: all 0.3s ease;
|
||
|
|
white-space: nowrap;
|
||
|
|
}
|
||
|
|
|
||
|
|
.category-item:hover {
|
||
|
|
transform: translateY(-2px);
|
||
|
|
box-shadow: 0 4px 6px var(--shadow-color);
|
||
|
|
}
|
||
|
|
|
||
|
|
.category-item.active {
|
||
|
|
background: var(--primary-color);
|
||
|
|
color: white;
|
||
|
|
}
|
||
|
|
|
||
|
|
.template-grid {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||
|
|
gap: 2rem;
|
||
|
|
margin-bottom: 3rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.template-card {
|
||
|
|
border-radius: 12px;
|
||
|
|
background: white;
|
||
|
|
box-shadow: 0 2px 4px var(--shadow-color);
|
||
|
|
transition: all 0.3s ease;
|
||
|
|
overflow: hidden;
|
||
|
|
}
|
||
|
|
|
||
|
|
.template-card:hover {
|
||
|
|
transform: translateY(-5px);
|
||
|
|
box-shadow: 0 8px 16px var(--shadow-color);
|
||
|
|
}
|
||
|
|
|
||
|
|
.card-header {
|
||
|
|
padding: 1.25rem;
|
||
|
|
border-bottom: 1px solid var(--border-color);
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 1rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.card-header i {
|
||
|
|
font-size: 1.5rem;
|
||
|
|
color: var(--primary-color);
|
||
|
|
}
|
||
|
|
|
||
|
|
.card-body {
|
||
|
|
padding: 1.25rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.description {
|
||
|
|
color: #64748b;
|
||
|
|
margin-bottom: 1rem;
|
||
|
|
line-height: 1.5;
|
||
|
|
}
|
||
|
|
|
||
|
|
.tags {
|
||
|
|
display: flex;
|
||
|
|
flex-wrap: wrap;
|
||
|
|
gap: 0.5rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.tag {
|
||
|
|
padding: 0.4rem 0.8rem;
|
||
|
|
border-radius: 999px;
|
||
|
|
font-size: 0.875rem;
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 0.5rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.tag.industry {
|
||
|
|
background: #dbeafe;
|
||
|
|
color: #1e40af;
|
||
|
|
}
|
||
|
|
|
||
|
|
.tag.profession {
|
||
|
|
background: #dcfce7;
|
||
|
|
color: #166534;
|
||
|
|
}
|
||
|
|
|
||
|
|
.card-footer {
|
||
|
|
padding: 1.25rem;
|
||
|
|
border-top: 1px solid var(--border-color);
|
||
|
|
display: flex;
|
||
|
|
justify-content: flex-end;
|
||
|
|
gap: 1rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-preview, .btn-use {
|
||
|
|
padding: 0.5rem 1rem;
|
||
|
|
border-radius: 6px;
|
||
|
|
border: none;
|
||
|
|
cursor: pointer;
|
||
|
|
transition: all 0.2s ease;
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 0.5rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-preview {
|
||
|
|
background: #f1f5f9;
|
||
|
|
color: var(--text-color);
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-use {
|
||
|
|
background: var(--primary-color);
|
||
|
|
color: white;
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-preview:hover {
|
||
|
|
background: #e2e8f0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-use:hover {
|
||
|
|
background: var(--secondary-color);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 响应式设计 */
|
||
|
|
@media (max-width: 768px) {
|
||
|
|
.container {
|
||
|
|
padding: 1rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.template-grid {
|
||
|
|
grid-template-columns: 1fr;
|
||
|
|
}
|
||
|
|
|
||
|
|
.page-header h1 {
|
||
|
|
font-size: 2rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.category-nav {
|
||
|
|
padding: 0.5rem;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 动画效果 */
|
||
|
|
@keyframes fadeIn {
|
||
|
|
from { opacity: 0; transform: translateY(20px); }
|
||
|
|
to { opacity: 1; transform: translateY(0); }
|
||
|
|
}
|
||
|
|
|
||
|
|
.template-card {
|
||
|
|
animation: fadeIn 0.5s ease-out;
|
||
|
|
}
|
||
|
|
</style>
|
||
|
|
{% endblock %}
|
||
|
|
|
||
|
|
{% block scripts %}
|
||
|
|
<script>
|
||
|
|
document.addEventListener('DOMContentLoaded', function() {
|
||
|
|
// 搜索功能
|
||
|
|
const searchInput = document.getElementById('templateSearch');
|
||
|
|
const templateContainer = document.getElementById('templateContainer');
|
||
|
|
const templateCards = templateContainer.getElementsByClassName('template-card');
|
||
|
|
|
||
|
|
searchInput.addEventListener('input', function(e) {
|
||
|
|
const searchTerm = e.target.value.toLowerCase();
|
||
|
|
|
||
|
|
Array.from(templateCards).forEach(card => {
|
||
|
|
const title = card.querySelector('h3').textContent.toLowerCase();
|
||
|
|
const description = card.querySelector('.description').textContent.toLowerCase();
|
||
|
|
|
||
|
|
if (title.includes(searchTerm) || description.includes(searchTerm)) {
|
||
|
|
card.style.display = '';
|
||
|
|
} else {
|
||
|
|
card.style.display = 'none';
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// 视图切换
|
||
|
|
const viewButtons = document.querySelectorAll('.view-btn');
|
||
|
|
viewButtons.forEach(btn => {
|
||
|
|
btn.addEventListener('click', function() {
|
||
|
|
viewButtons.forEach(b => b.classList.remove('active'));
|
||
|
|
this.classList.add('active');
|
||
|
|
|
||
|
|
const viewType = this.dataset.view;
|
||
|
|
templateContainer.className = `template-${viewType}`;
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// 模板预览
|
||
|
|
const modal = document.getElementById('previewModal');
|
||
|
|
const closeBtn = modal.querySelector('.close');
|
||
|
|
|
||
|
|
window.previewTemplate = function(templateId) {
|
||
|
|
modal.style.display = 'block';
|
||
|
|
// 这里添加获取模板预览数据的逻辑
|
||
|
|
}
|
||
|
|
|
||
|
|
closeBtn.onclick = function() {
|
||
|
|
modal.style.display = 'none';
|
||
|
|
}
|
||
|
|
|
||
|
|
window.onclick = function(event) {
|
||
|
|
if (event.target == modal) {
|
||
|
|
modal.style.display = 'none';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
</script>
|
||
|
|
{% endblock %}
|