1235 lines
35 KiB
HTML
1235 lines
35 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}提示词大师{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="hero">
|
|
<div class="hero-content">
|
|
<h1>提示词大师</h1>
|
|
<p class="subtitle">让AI更好地理解您的需求</p>
|
|
<div class="hero-decoration"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="container mt-4">
|
|
<div class="row">
|
|
<div class="col-md-8 offset-md-2">
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h2>提示词生成器</h2>
|
|
<a href="{{ url_for('main.expert_generate') }}" class="btn btn-primary">
|
|
<i class="fas fa-brain"></i> 专家模式
|
|
</a>
|
|
</div>
|
|
<form method="POST" class="generate-form">
|
|
{{ form.hidden_tag() }}
|
|
|
|
<div class="search-section">
|
|
<div class="search-box">
|
|
<input type="text" id="templateSearch" class="search-input" placeholder="搜索模板名称或描述...">
|
|
<i class="fas fa-search search-icon"></i>
|
|
</div>
|
|
<div class="search-stats">
|
|
<span class="search-count"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="templates-section">
|
|
<div class="section-header">
|
|
<h2>选择场景</h2>
|
|
<div class="filter-controls">
|
|
<select id="industryFilter" class="custom-select">
|
|
<option value="all">全部行业</option>
|
|
{% for industry in industries %}
|
|
<option value="{{ industry }}">{{ industry }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<select id="professionFilter" class="custom-select">
|
|
<option value="all">全部职业</option>
|
|
{% for profession in professions %}
|
|
<option value="{{ profession }}">{{ profession }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<select id="subCategoryFilter" class="custom-select">
|
|
<option value="all">全部领域</option>
|
|
{% for sub_category in sub_categories %}
|
|
<option value="{{ sub_category }}">{{ sub_category }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="category-tabs">
|
|
<div class="tab active" data-category="all">全部</div>
|
|
{% for category in categories %}
|
|
<div class="tab" data-category="{{ category }}">{{ category }}</div>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<div class="template-grid">
|
|
{% for template in templates %}
|
|
<div class="template-card"
|
|
data-category="{{ template.category }}"
|
|
data-industry="{{ template.industry }}"
|
|
data-profession="{{ template.profession }}"
|
|
data-subcategory="{{ template.sub_category }}">
|
|
<input type="radio" name="template_id" id="template_{{ template.id }}"
|
|
value="{{ template.id }}"
|
|
{% if template.is_default %}checked{% endif %}>
|
|
<label for="template_{{ template.id }}" class="template-content">
|
|
<div class="template-actions">
|
|
<button type="button" class="btn-delete"
|
|
data-template-id="{{ template.id }}"
|
|
title="删除模板">
|
|
<i class="fas fa-trash-alt"></i>
|
|
</button>
|
|
</div>
|
|
<div class="template-categories">
|
|
<div class="category-group">
|
|
<span class="category-label">行业:</span>
|
|
<span class="category-value">{{ template.industry }}</span>
|
|
</div>
|
|
<div class="category-group">
|
|
<span class="category-label">职业:</span>
|
|
<span class="category-value">{{ template.profession }}</span>
|
|
</div>
|
|
<div class="category-group">
|
|
<span class="category-label">领域:</span>
|
|
<span class="category-value">{{ template.sub_category }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="template-header">
|
|
<div class="template-icon">
|
|
<i class="fas {{ get_template_icon(template.category) }}"></i>
|
|
</div>
|
|
<h3>{{ template.name }}</h3>
|
|
</div>
|
|
|
|
<div class="template-info">
|
|
<p>{{ template.description }}</p>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="input-section">
|
|
<div class="section-header">
|
|
<h2>输入需求</h2>
|
|
<span class="subtitle">描述越详细,生成的提示词效果越好</span>
|
|
</div>
|
|
{{ form.input_text(class="form-control custom-textarea", rows=5,
|
|
placeholder="请详细描述您的需求...") }}
|
|
</div>
|
|
|
|
<div class="action-section">
|
|
{{ form.submit(class="btn btn-primary btn-generate", value="生成专业提示词") }}
|
|
</div>
|
|
</form>
|
|
|
|
{% if prompt %}
|
|
<div class="result-section">
|
|
<div class="result-card">
|
|
<div class="result-header">
|
|
<h2>生成结果</h2>
|
|
<div class="result-actions">
|
|
<button class="btn btn-copy" onclick="copyText('{{ prompt.generated_text }}')">
|
|
<i class="fas fa-copy"></i>
|
|
复制提示词
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="result-content">
|
|
<div class="output-preview">
|
|
<div class="text-content">{{ prompt.generated_text }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="filter-stats">
|
|
<div class="stat-item">
|
|
<span class="stat-label">行业:</span>
|
|
<span class="stat-value">{{ industries|length }}</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="stat-label">职业:</span>
|
|
<span class="stat-value">{{ professions|length }}</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="stat-label">领域:</span>
|
|
<span class="stat-value">{{ sub_categories|length }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="deleteModal" class="modal">
|
|
<div class="modal-content">
|
|
<h3>确认删除</h3>
|
|
<p>确定要删除这个提示词模板吗?此操作无法撤销。</p>
|
|
<div class="modal-actions">
|
|
<button class="btn-cancel">取消</button>
|
|
<button class="btn-confirm">确认删除</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
:root {
|
|
--primary-color: #4a90e2;
|
|
--primary-dark: #357abd;
|
|
--secondary-color: #f5f7fa;
|
|
--text-color: #2c3e50;
|
|
--border-color: #e0e0e0;
|
|
--hover-color: #e8f0fe;
|
|
--success-color: #4CAF50;
|
|
--success-dark: #45a049;
|
|
}
|
|
|
|
.hero {
|
|
background: linear-gradient(135deg, var(--primary-color), #6aa9f7);
|
|
padding: 4rem 0;
|
|
margin-bottom: 3rem;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.hero-content {
|
|
text-align: center;
|
|
color: white;
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
.hero h1 {
|
|
font-size: 3rem;
|
|
margin-bottom: 1rem;
|
|
font-weight: 700;
|
|
text-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.hero .subtitle {
|
|
font-size: 1.2rem;
|
|
opacity: 0.9;
|
|
max-width: 600px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.hero-decoration {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 18c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm48 25c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm-43-7c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm63 31c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 90c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm56-76c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM12 86c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm28-65c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm23-11c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-6 60c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm29 22c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zM32 63c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm57-13c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-9-21c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM60 91c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM35 41c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM12 60c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z' fill='%23ffffff' fill-opacity='0.1' fill-rule='evenodd'/%3E%3C/svg%3E");
|
|
opacity: 0.1;
|
|
}
|
|
|
|
.main-container {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 0 2rem;
|
|
}
|
|
|
|
.section-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.section-header h2 {
|
|
font-size: 1.5rem;
|
|
color: var(--text-color);
|
|
margin: 0;
|
|
}
|
|
|
|
.filter-controls {
|
|
display: flex;
|
|
gap: 1rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.custom-select {
|
|
padding: 0.5rem 1rem;
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 6px;
|
|
background: white;
|
|
min-width: 150px;
|
|
}
|
|
|
|
.category-tabs {
|
|
display: flex;
|
|
gap: 1rem;
|
|
margin-bottom: 2rem;
|
|
border-bottom: 1px solid var(--border-color);
|
|
padding-bottom: 0.5rem;
|
|
}
|
|
|
|
.tab {
|
|
padding: 0.5rem 1rem;
|
|
cursor: pointer;
|
|
border-radius: 6px;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.tab.active {
|
|
background: var(--primary-color);
|
|
color: white;
|
|
}
|
|
|
|
.template-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
gap: 1.5rem;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.template-card {
|
|
position: relative;
|
|
transition: transform 0.2s, box-shadow 0.2s;
|
|
}
|
|
|
|
.template-content {
|
|
display: flex;
|
|
padding: 1.5rem;
|
|
background: white;
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 12px;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
height: 100%;
|
|
}
|
|
|
|
.template-content:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|
border-color: var(--primary-color);
|
|
}
|
|
|
|
.template-icon {
|
|
font-size: 1.5rem;
|
|
color: var(--primary-color);
|
|
margin-right: 1rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 48px;
|
|
height: 48px;
|
|
background: var(--hover-color);
|
|
border-radius: 12px;
|
|
}
|
|
|
|
.template-info {
|
|
flex: 1;
|
|
}
|
|
|
|
.template-info h3 {
|
|
margin: 0 0 0.5rem;
|
|
font-size: 1.1rem;
|
|
color: var(--text-color);
|
|
}
|
|
|
|
.template-info p {
|
|
margin: 0 0 1rem;
|
|
font-size: 0.9rem;
|
|
color: #666;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.template-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.template-tags {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.tag {
|
|
font-size: 0.75rem;
|
|
padding: 0.25rem 0.5rem;
|
|
border-radius: 4px;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.tag.industry {
|
|
background: #e3f2fd;
|
|
color: #1976d2;
|
|
}
|
|
|
|
.tag.profession {
|
|
background: #f3e5f5;
|
|
color: #7b1fa2;
|
|
}
|
|
|
|
.subcategory-tag {
|
|
display: inline-block;
|
|
margin-top: 0.5rem;
|
|
padding: 0.25rem 0.75rem;
|
|
background: #f5f5f5;
|
|
border-radius: 20px;
|
|
font-size: 0.8rem;
|
|
color: #666;
|
|
}
|
|
|
|
.custom-textarea {
|
|
width: 100%;
|
|
padding: 1rem;
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 12px;
|
|
resize: vertical;
|
|
min-height: 120px;
|
|
font-size: 1rem;
|
|
line-height: 1.6;
|
|
transition: border-color 0.3s;
|
|
}
|
|
|
|
.custom-textarea:focus {
|
|
outline: none;
|
|
border-color: var(--primary-color);
|
|
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
|
|
}
|
|
|
|
.btn-generate {
|
|
background: var(--primary-color);
|
|
color: white;
|
|
padding: 1rem 2rem;
|
|
font-size: 1.1rem;
|
|
border-radius: 8px;
|
|
border: none;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
width: 100%;
|
|
max-width: 300px;
|
|
margin: 2rem auto;
|
|
display: block;
|
|
}
|
|
|
|
.btn-generate:hover {
|
|
background: var(--primary-dark);
|
|
transform: translateY(-1px);
|
|
box-shadow: 0 4px 12px rgba(74, 144, 226, 0.2);
|
|
}
|
|
|
|
.result-card {
|
|
background: white;
|
|
border-radius: 16px;
|
|
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
|
|
padding: 2rem;
|
|
margin-top: 2rem;
|
|
animation: slideUp 0.5s ease-out;
|
|
}
|
|
|
|
@keyframes slideUp {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(20px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
.result-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 1.5rem;
|
|
padding-bottom: 1rem;
|
|
border-bottom: 1px solid var(--border-color);
|
|
}
|
|
|
|
.text-content {
|
|
background: var(--secondary-color);
|
|
padding: 1.5rem;
|
|
border-radius: 12px;
|
|
white-space: pre-wrap;
|
|
font-size: 1rem;
|
|
line-height: 1.6;
|
|
color: var(--text-color);
|
|
}
|
|
|
|
.filter-stats {
|
|
display: flex;
|
|
gap: 2rem;
|
|
margin: 1rem 0;
|
|
padding: 1rem;
|
|
background: #f8f9fa;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.stat-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.stat-label {
|
|
color: #666;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.stat-value {
|
|
font-weight: bold;
|
|
color: var(--primary-color);
|
|
}
|
|
|
|
.template-categories {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
margin-bottom: 12px;
|
|
padding: 8px;
|
|
background: #f8f9fa;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.category-group {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
padding: 4px 8px;
|
|
background: white;
|
|
border-radius: 4px;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.category-label {
|
|
color: #666;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.category-value {
|
|
color: var(--primary-color);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.template-card {
|
|
background: white;
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 12px;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.template-card:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|
border-color: var(--primary-color);
|
|
}
|
|
|
|
.template-content {
|
|
padding: 16px;
|
|
cursor: pointer;
|
|
display: block;
|
|
}
|
|
|
|
.template-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.template-header h3 {
|
|
margin: 0;
|
|
font-size: 1.1rem;
|
|
color: var(--text-color);
|
|
}
|
|
|
|
.template-info p {
|
|
margin: 0;
|
|
font-size: 0.9rem;
|
|
color: #666;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.filter-active {
|
|
background: var(--primary-color);
|
|
color: white;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.hero {
|
|
padding: 3rem 1rem;
|
|
}
|
|
|
|
.hero h1 {
|
|
font-size: 2rem;
|
|
}
|
|
|
|
.main-container {
|
|
padding: 0 1rem;
|
|
}
|
|
|
|
.template-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.section-header {
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.result-header {
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.btn-generate {
|
|
width: 100%;
|
|
}
|
|
|
|
.filter-controls {
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.category-tabs {
|
|
overflow-x: auto;
|
|
padding-bottom: 0.5rem;
|
|
}
|
|
|
|
.tab {
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.filter-stats {
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.template-tags {
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.template-categories {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.category-group {
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
.filter-active {
|
|
border-color: var(--primary-color);
|
|
background-color: var(--hover-color);
|
|
}
|
|
|
|
.no-results {
|
|
width: 100%;
|
|
padding: 3rem;
|
|
text-align: center;
|
|
}
|
|
|
|
.no-results-content {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.no-results i {
|
|
font-size: 2rem;
|
|
color: #999;
|
|
}
|
|
|
|
.no-results h3 {
|
|
margin: 0;
|
|
color: #666;
|
|
}
|
|
|
|
.no-results p {
|
|
margin: 0;
|
|
color: #999;
|
|
}
|
|
|
|
.btn-reset-filters {
|
|
padding: 0.5rem 1rem;
|
|
background: var(--primary-color);
|
|
color: white;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.btn-reset-filters:hover {
|
|
background: var(--primary-dark);
|
|
}
|
|
|
|
.filter-stats {
|
|
background: white;
|
|
border: 1px solid var(--border-color);
|
|
padding: 1rem;
|
|
border-radius: 8px;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.stat-item {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.25rem 0.75rem;
|
|
background: var(--secondary-color);
|
|
border-radius: 4px;
|
|
margin-right: 0.5rem;
|
|
}
|
|
|
|
.search-section {
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.search-box {
|
|
position: relative;
|
|
max-width: 600px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.search-input {
|
|
width: 100%;
|
|
padding: 12px 40px 12px 16px;
|
|
border: 2px solid var(--border-color);
|
|
border-radius: 8px;
|
|
font-size: 1rem;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.search-input:focus {
|
|
outline: none;
|
|
border-color: var(--primary-color);
|
|
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
|
|
}
|
|
|
|
.search-icon {
|
|
position: absolute;
|
|
right: 12px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
color: #999;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.search-stats {
|
|
margin-top: 0.5rem;
|
|
text-align: center;
|
|
font-size: 0.9rem;
|
|
color: #666;
|
|
}
|
|
|
|
.highlight {
|
|
background-color: rgba(255, 247, 0, 0.3);
|
|
padding: 0 2px;
|
|
border-radius: 2px;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.search-box {
|
|
margin: 0;
|
|
}
|
|
}
|
|
|
|
.template-actions {
|
|
position: absolute;
|
|
top: 1rem;
|
|
right: 1rem;
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
.template-card:hover .template-actions {
|
|
opacity: 1;
|
|
}
|
|
|
|
.btn-delete {
|
|
padding: 0.5rem;
|
|
background: none;
|
|
border: none;
|
|
color: #dc3545;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.btn-delete:hover {
|
|
color: #c82333;
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
.modal {
|
|
display: none;
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
z-index: 1000;
|
|
}
|
|
|
|
.modal-content {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
background: white;
|
|
padding: 2rem;
|
|
border-radius: 8px;
|
|
min-width: 300px;
|
|
text-align: center;
|
|
}
|
|
|
|
.modal-actions {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 1rem;
|
|
margin-top: 1.5rem;
|
|
}
|
|
|
|
.btn-cancel {
|
|
padding: 0.5rem 1.5rem;
|
|
background: #6c757d;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.btn-confirm {
|
|
padding: 0.5rem 1.5rem;
|
|
background: #dc3545;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const industryFilter = document.getElementById('industryFilter');
|
|
const professionFilter = document.getElementById('professionFilter');
|
|
const subCategoryFilter = document.getElementById('subCategoryFilter');
|
|
const tabs = document.querySelectorAll('.tab');
|
|
|
|
// 更新筛选状态显示
|
|
function updateFilterStatus() {
|
|
const industry = industryFilter.value;
|
|
const profession = professionFilter.value;
|
|
const subCategory = subCategoryFilter.value;
|
|
|
|
// 更新选中状态样式
|
|
document.querySelectorAll('.filter-controls select').forEach(select => {
|
|
if (select.value !== 'all') {
|
|
select.classList.add('filter-active');
|
|
} else {
|
|
select.classList.remove('filter-active');
|
|
}
|
|
});
|
|
|
|
// 更新统计信息
|
|
const visibleCards = document.querySelectorAll('.template-card:not(.hidden)');
|
|
const totalCards = document.querySelectorAll('.template-card');
|
|
|
|
document.querySelector('.filter-stats').innerHTML = `
|
|
<div class="stat-item">
|
|
<span class="stat-label">当前筛选:</span>
|
|
<span class="stat-value">${visibleCards.length}/${totalCards.length}</span>
|
|
</div>
|
|
${industry !== 'all' ? `
|
|
<div class="stat-item">
|
|
<span class="stat-label">行业:</span>
|
|
<span class="stat-value">${industry}</span>
|
|
</div>
|
|
` : ''}
|
|
${profession !== 'all' ? `
|
|
<div class="stat-item">
|
|
<span class="stat-label">职业:</span>
|
|
<span class="stat-value">${profession}</span>
|
|
</div>
|
|
` : ''}
|
|
${subCategory !== 'all' ? `
|
|
<div class="stat-item">
|
|
<span class="stat-label">领域:</span>
|
|
<span class="stat-value">${subCategory}</span>
|
|
</div>
|
|
` : ''}
|
|
`;
|
|
}
|
|
|
|
// 改进的筛选逻辑
|
|
function filterTemplates() {
|
|
const industry = industryFilter.value;
|
|
const profession = professionFilter.value;
|
|
const subCategory = subCategoryFilter.value;
|
|
const category = document.querySelector('.tab.active').dataset.category;
|
|
|
|
const cards = document.querySelectorAll('.template-card');
|
|
let hasVisibleCards = false;
|
|
|
|
cards.forEach(card => {
|
|
const matchIndustry = industry === 'all' || card.dataset.industry === industry;
|
|
const matchProfession = profession === 'all' || card.dataset.profession === profession;
|
|
const matchSubCategory = subCategory === 'all' || card.dataset.subcategory === subCategory;
|
|
const matchCategory = category === 'all' || card.dataset.category === category;
|
|
|
|
if (matchIndustry && matchProfession && matchSubCategory && matchCategory) {
|
|
card.classList.remove('hidden');
|
|
card.style.display = '';
|
|
hasVisibleCards = true;
|
|
} else {
|
|
card.classList.add('hidden');
|
|
card.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
// 显示无结果提示
|
|
const noResultsEl = document.querySelector('.no-results');
|
|
if (!hasVisibleCards) {
|
|
if (!noResultsEl) {
|
|
const noResults = document.createElement('div');
|
|
noResults.className = 'no-results';
|
|
noResults.innerHTML = `
|
|
<div class="no-results-content">
|
|
<i class="fas fa-search"></i>
|
|
<h3>未找到匹配的模板</h3>
|
|
<p>请尝试调整筛选条件</p>
|
|
<button class="btn-reset-filters">重置筛选</button>
|
|
</div>
|
|
`;
|
|
document.querySelector('.template-grid').appendChild(noResults);
|
|
|
|
// 绑定重置按钮事件
|
|
noResults.querySelector('.btn-reset-filters').addEventListener('click', resetFilters);
|
|
}
|
|
} else if (noResultsEl) {
|
|
noResultsEl.remove();
|
|
}
|
|
|
|
updateFilterStatus();
|
|
}
|
|
|
|
// 重置筛选条件
|
|
function resetFilters() {
|
|
industryFilter.value = 'all';
|
|
professionFilter.value = 'all';
|
|
subCategoryFilter.value = 'all';
|
|
document.querySelector('.tab.active').classList.remove('active');
|
|
document.querySelector('[data-category="all"]').classList.add('active');
|
|
filterTemplates();
|
|
}
|
|
|
|
// 绑定事件
|
|
[industryFilter, professionFilter, subCategoryFilter].forEach(filter => {
|
|
filter.addEventListener('change', filterTemplates);
|
|
});
|
|
|
|
tabs.forEach(tab => {
|
|
tab.addEventListener('click', () => {
|
|
tabs.forEach(t => t.classList.remove('active'));
|
|
tab.classList.add('active');
|
|
filterTemplates();
|
|
});
|
|
});
|
|
|
|
// 初始化筛选
|
|
filterTemplates();
|
|
});
|
|
|
|
function copyText(text) {
|
|
// 创建临时文本区域
|
|
const textArea = document.createElement('textarea');
|
|
textArea.value = text;
|
|
document.body.appendChild(textArea);
|
|
|
|
try {
|
|
// 选择文本
|
|
textArea.select();
|
|
textArea.setSelectionRange(0, 99999); // 对于移动设备
|
|
|
|
// 尝试使用新的 API
|
|
if (navigator.clipboard && window.isSecureContext) {
|
|
// 对于现代浏览器
|
|
navigator.clipboard.writeText(text).then(() => {
|
|
showCopySuccess();
|
|
}).catch(err => {
|
|
console.error('复制失败:', err);
|
|
// 回退到传统方法
|
|
document.execCommand('copy');
|
|
showCopySuccess();
|
|
});
|
|
} else {
|
|
// 对于不支持 Clipboard API 的浏览器
|
|
const successful = document.execCommand('copy');
|
|
if (successful) {
|
|
showCopySuccess();
|
|
} else {
|
|
console.error('复制失败');
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.error('复制出错:', err);
|
|
} finally {
|
|
// 清理临时元素
|
|
document.body.removeChild(textArea);
|
|
}
|
|
}
|
|
|
|
// 显示复制成功的反馈
|
|
function showCopySuccess() {
|
|
const copyBtn = document.querySelector('.btn-copy');
|
|
if (copyBtn) {
|
|
const originalText = copyBtn.innerHTML;
|
|
copyBtn.innerHTML = '<i class="fas fa-check"></i> 已复制';
|
|
copyBtn.classList.add('copied');
|
|
|
|
setTimeout(() => {
|
|
copyBtn.innerHTML = originalText;
|
|
copyBtn.classList.remove('copied');
|
|
}, 2000);
|
|
}
|
|
}
|
|
|
|
// 添加按钮样式
|
|
const style = document.createElement('style');
|
|
style.textContent = `
|
|
.btn-copy {
|
|
padding: 8px 16px;
|
|
background: #4CAF50;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.btn-copy:hover {
|
|
background: #45a049;
|
|
}
|
|
|
|
.btn-copy.copied {
|
|
background: #45a049;
|
|
}
|
|
|
|
.btn-copy i {
|
|
margin-right: 6px;
|
|
}
|
|
`;
|
|
document.head.appendChild(style);
|
|
|
|
// 确保在DOM加载完成后绑定事件
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const copyButtons = document.querySelectorAll('.btn-copy');
|
|
copyButtons.forEach(button => {
|
|
button.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
const text = this.closest('.result-card').querySelector('.text-content').textContent;
|
|
copyText(text);
|
|
});
|
|
});
|
|
});
|
|
|
|
// 添加搜索功能
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const searchInput = document.getElementById('templateSearch');
|
|
const searchStats = document.querySelector('.search-count');
|
|
|
|
function highlightText(text, searchTerm) {
|
|
if (!searchTerm) return text;
|
|
const regex = new RegExp(`(${searchTerm})`, 'gi');
|
|
return text.replace(regex, '<span class="highlight">$1</span>');
|
|
}
|
|
|
|
function updateSearchStats(visibleCount, totalCount) {
|
|
searchStats.textContent = `显示 ${visibleCount}/${totalCount} 个模板`;
|
|
}
|
|
|
|
function searchTemplates() {
|
|
const searchTerm = searchInput.value.toLowerCase().trim();
|
|
const cards = document.querySelectorAll('.template-card');
|
|
let visibleCount = 0;
|
|
|
|
cards.forEach(card => {
|
|
const name = card.querySelector('h3').textContent.toLowerCase();
|
|
const description = card.querySelector('p').textContent.toLowerCase();
|
|
const industry = card.dataset.industry.toLowerCase();
|
|
const profession = card.dataset.profession.toLowerCase();
|
|
const category = card.dataset.category.toLowerCase();
|
|
const subCategory = card.dataset.subcategory.toLowerCase();
|
|
|
|
const matchSearch = !searchTerm ||
|
|
name.includes(searchTerm) ||
|
|
description.includes(searchTerm) ||
|
|
industry.includes(searchTerm) ||
|
|
profession.includes(searchTerm) ||
|
|
category.includes(searchTerm) ||
|
|
subCategory.includes(searchTerm);
|
|
|
|
// 检查筛选条件
|
|
const matchFilters = checkFilters(card);
|
|
|
|
if (matchSearch && matchFilters) {
|
|
card.style.display = '';
|
|
visibleCount++;
|
|
|
|
// 高亮匹配文本
|
|
if (searchTerm) {
|
|
card.querySelector('h3').innerHTML = highlightText(card.querySelector('h3').textContent, searchTerm);
|
|
card.querySelector('p').innerHTML = highlightText(card.querySelector('p').textContent, searchTerm);
|
|
}
|
|
} else {
|
|
card.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
updateSearchStats(visibleCount, cards.length);
|
|
|
|
// 显示无结果提示
|
|
const noResultsEl = document.querySelector('.no-results');
|
|
if (visibleCount === 0) {
|
|
if (!noResultsEl) {
|
|
const noResults = document.createElement('div');
|
|
noResults.className = 'no-results';
|
|
noResults.innerHTML = `
|
|
<div class="no-results-content">
|
|
<i class="fas fa-search"></i>
|
|
<h3>未找到匹配的模板</h3>
|
|
<p>请尝试其他搜索关键词</p>
|
|
<button class="btn-reset-search">清除搜索</button>
|
|
</div>
|
|
`;
|
|
document.querySelector('.template-grid').appendChild(noResults);
|
|
|
|
// 绑定清除搜索按钮事件
|
|
noResults.querySelector('.btn-reset-search').addEventListener('click', () => {
|
|
searchInput.value = '';
|
|
searchTemplates();
|
|
});
|
|
}
|
|
} else if (noResultsEl) {
|
|
noResultsEl.remove();
|
|
}
|
|
}
|
|
|
|
function checkFilters(card) {
|
|
const industry = document.getElementById('industryFilter').value;
|
|
const profession = document.getElementById('professionFilter').value;
|
|
const subCategory = document.getElementById('subCategoryFilter').value;
|
|
const category = document.querySelector('.tab.active').dataset.category;
|
|
|
|
return (industry === 'all' || card.dataset.industry === industry) &&
|
|
(profession === 'all' || card.dataset.profession === profession) &&
|
|
(subCategory === 'all' || card.dataset.subcategory === subCategory) &&
|
|
(category === 'all' || card.dataset.category === category);
|
|
}
|
|
|
|
// 防抖函数
|
|
function debounce(func, wait) {
|
|
let timeout;
|
|
return function() {
|
|
const context = this;
|
|
const args = arguments;
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(() => func.apply(context, args), wait);
|
|
};
|
|
}
|
|
|
|
// 绑定搜索事件
|
|
searchInput.addEventListener('input', debounce(searchTemplates, 300));
|
|
|
|
// 初始化搜索统计
|
|
updateSearchStats(document.querySelectorAll('.template-card').length,
|
|
document.querySelectorAll('.template-card').length);
|
|
});
|
|
|
|
// 添加删除功能相关的脚本
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const modal = document.getElementById('deleteModal');
|
|
const btnCancel = modal.querySelector('.btn-cancel');
|
|
const btnConfirm = modal.querySelector('.btn-confirm');
|
|
let currentTemplateId = null;
|
|
|
|
// 显示删除确认框
|
|
function showDeleteModal(templateId) {
|
|
currentTemplateId = templateId;
|
|
modal.style.display = 'block';
|
|
}
|
|
|
|
// 隐藏删除确认框
|
|
function hideDeleteModal() {
|
|
modal.style.display = 'none';
|
|
currentTemplateId = null;
|
|
}
|
|
|
|
// 删除模板
|
|
async function deleteTemplate(templateId) {
|
|
try {
|
|
const response = await fetch(`/api/templates/${templateId}`, {
|
|
method: 'DELETE',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': document.querySelector('input[name="csrf_token"]').value
|
|
}
|
|
});
|
|
|
|
if (response.ok) {
|
|
// 删除成功,移除对应的模板卡片
|
|
const card = document.querySelector(`[data-template-id="${templateId}"]`)
|
|
.closest('.template-card');
|
|
card.remove();
|
|
|
|
// 更新统计信息
|
|
updateSearchStats(
|
|
document.querySelectorAll('.template-card:not(.hidden)').length,
|
|
document.querySelectorAll('.template-card').length
|
|
);
|
|
} else {
|
|
throw new Error('删除失败');
|
|
}
|
|
} catch (error) {
|
|
console.error('删除模板时出错:', error);
|
|
alert('删除模板失败,请稍后重试');
|
|
} finally {
|
|
hideDeleteModal();
|
|
}
|
|
}
|
|
|
|
// 绑定删除按钮点击事件
|
|
document.querySelectorAll('.btn-delete').forEach(btn => {
|
|
btn.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
const templateId = btn.dataset.templateId;
|
|
showDeleteModal(templateId);
|
|
});
|
|
});
|
|
|
|
// 绑定取消按钮事件
|
|
btnCancel.addEventListener('click', hideDeleteModal);
|
|
|
|
// 绑定确认删除按钮事件
|
|
btnConfirm.addEventListener('click', () => {
|
|
if (currentTemplateId) {
|
|
deleteTemplate(currentTemplateId);
|
|
}
|
|
});
|
|
|
|
// 点击模态框外部关闭
|
|
modal.addEventListener('click', (e) => {
|
|
if (e.target === modal) {
|
|
hideDeleteModal();
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %} |