feat: 添加SEO工具管理页面 - v2.4.1
新增功能: 1. 后台SEO工具管理页面 (/admin/seo-tools) - 显示sitemap状态(是否存在、最后更新时间、文件大小) - 显示动态sitemap URL并支持一键复制 2. 生成静态sitemap.xml文件 (/api/generate-static-sitemap) - 将动态sitemap生成为static/sitemap.xml静态文件 - 支持手动触发更新 - 返回URL数量统计信息 3. 通知搜索引擎功能 (/api/notify-search-engines) - 支持向Google、Baidu、Bing提交sitemap更新通知 - 使用各搜索引擎的ping接口 - 返回每个搜索引擎的提交状态 4. 一键操作 - 提供"一键生成并通知"功能 - 自动执行生成sitemap + 通知搜索引擎两个步骤 - 适合日常SEO维护使用 技术实现: - 使用Flask路由和@login_required装饰器保护后台接口 - AJAX + fetch API实现前端交互 - Bootstrap 4卡片式UI设计 - 实时显示操作结果,颜色区分成功/失败状态 用户价值: - 无需手动登录各搜索引擎后台提交sitemap - 支持批量更新和通知,提升SEO工作效率 - 可视化状态展示,便于监控sitemap更新情况 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
174
app.py
174
app.py
@@ -806,6 +806,180 @@ Sitemap: {}sitemap.xml
|
||||
response.headers['Content-Type'] = 'text/plain; charset=utf-8'
|
||||
return response
|
||||
|
||||
# ========== SEO工具管理路由 (v2.4新增) ==========
|
||||
@app.route('/admin/seo-tools')
|
||||
@login_required
|
||||
def seo_tools():
|
||||
"""SEO工具管理页面"""
|
||||
# 检查static/sitemap.xml是否存在及最后更新时间
|
||||
sitemap_path = 'static/sitemap.xml'
|
||||
sitemap_info = None
|
||||
if os.path.exists(sitemap_path):
|
||||
import time
|
||||
mtime = os.path.getmtime(sitemap_path)
|
||||
sitemap_info = {
|
||||
'exists': True,
|
||||
'last_updated': datetime.fromtimestamp(mtime).strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'size': os.path.getsize(sitemap_path)
|
||||
}
|
||||
else:
|
||||
sitemap_info = {'exists': False}
|
||||
|
||||
return render_template('admin/seo_tools.html', sitemap_info=sitemap_info)
|
||||
|
||||
@app.route('/api/generate-static-sitemap', methods=['POST'])
|
||||
@login_required
|
||||
def generate_static_sitemap():
|
||||
"""生成静态sitemap.xml文件"""
|
||||
try:
|
||||
# 获取所有启用的网站
|
||||
sites = Site.query.filter_by(is_active=True).order_by(Site.updated_at.desc()).all()
|
||||
|
||||
# 获取所有标签
|
||||
tags = Tag.query.all()
|
||||
|
||||
# 构建XML内容(使用网站配置的域名)
|
||||
base_url = request.url_root.rstrip('/')
|
||||
|
||||
xml_content = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'''
|
||||
|
||||
# 首页
|
||||
xml_content += f'''
|
||||
<url>
|
||||
<loc>{base_url}</loc>
|
||||
<changefreq>daily</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>'''
|
||||
|
||||
# 工具详情页
|
||||
for site in sites:
|
||||
xml_content += f'''
|
||||
<url>
|
||||
<loc>{base_url}/site/{site.code}</loc>
|
||||
<lastmod>{site.updated_at.strftime('%Y-%m-%d') if site.updated_at else datetime.now().strftime('%Y-%m-%d')}</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>'''
|
||||
|
||||
# 标签页
|
||||
for tag in tags:
|
||||
xml_content += f'''
|
||||
<url>
|
||||
<loc>{base_url}/?tag={tag.slug}</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>'''
|
||||
|
||||
xml_content += '''
|
||||
</urlset>'''
|
||||
|
||||
# 保存到static目录
|
||||
static_dir = 'static'
|
||||
os.makedirs(static_dir, exist_ok=True)
|
||||
sitemap_path = os.path.join(static_dir, 'sitemap.xml')
|
||||
|
||||
with open(sitemap_path, 'w', encoding='utf-8') as f:
|
||||
f.write(xml_content)
|
||||
|
||||
# 统计信息
|
||||
total_urls = 1 + len(sites) + len(tags) # 首页 + 工具页 + 标签页
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': f'静态sitemap.xml生成成功!共包含 {total_urls} 个URL',
|
||||
'total_urls': total_urls,
|
||||
'file_path': sitemap_path,
|
||||
'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'生成失败: {str(e)}'
|
||||
}), 500
|
||||
|
||||
@app.route('/api/notify-search-engines', methods=['POST'])
|
||||
@login_required
|
||||
def notify_search_engines():
|
||||
"""通知搜索引擎sitemap更新"""
|
||||
try:
|
||||
import requests
|
||||
from urllib.parse import quote
|
||||
|
||||
# 获取sitemap URL(使用当前请求的域名)
|
||||
sitemap_url = request.url_root.rstrip('/') + '/sitemap.xml'
|
||||
encoded_sitemap_url = quote(sitemap_url, safe='')
|
||||
|
||||
results = []
|
||||
|
||||
# 1. 通知Google
|
||||
google_ping_url = f'http://www.google.com/ping?sitemap={encoded_sitemap_url}'
|
||||
try:
|
||||
google_response = requests.get(google_ping_url, timeout=10)
|
||||
results.append({
|
||||
'engine': 'Google',
|
||||
'status': 'success' if google_response.status_code == 200 else 'failed',
|
||||
'status_code': google_response.status_code,
|
||||
'message': '提交成功' if google_response.status_code == 200 else f'HTTP {google_response.status_code}'
|
||||
})
|
||||
except Exception as e:
|
||||
results.append({
|
||||
'engine': 'Google',
|
||||
'status': 'error',
|
||||
'message': f'请求失败: {str(e)}'
|
||||
})
|
||||
|
||||
# 2. 通知Baidu
|
||||
baidu_ping_url = f'http://data.zz.baidu.com/ping?sitemap={encoded_sitemap_url}'
|
||||
try:
|
||||
baidu_response = requests.get(baidu_ping_url, timeout=10)
|
||||
results.append({
|
||||
'engine': 'Baidu',
|
||||
'status': 'success' if baidu_response.status_code == 200 else 'failed',
|
||||
'status_code': baidu_response.status_code,
|
||||
'message': '提交成功' if baidu_response.status_code == 200 else f'HTTP {baidu_response.status_code}'
|
||||
})
|
||||
except Exception as e:
|
||||
results.append({
|
||||
'engine': 'Baidu',
|
||||
'status': 'error',
|
||||
'message': f'请求失败: {str(e)}'
|
||||
})
|
||||
|
||||
# 3. 通知Bing
|
||||
bing_ping_url = f'http://www.bing.com/ping?sitemap={encoded_sitemap_url}'
|
||||
try:
|
||||
bing_response = requests.get(bing_ping_url, timeout=10)
|
||||
results.append({
|
||||
'engine': 'Bing',
|
||||
'status': 'success' if bing_response.status_code == 200 else 'failed',
|
||||
'status_code': bing_response.status_code,
|
||||
'message': '提交成功' if bing_response.status_code == 200 else f'HTTP {bing_response.status_code}'
|
||||
})
|
||||
except Exception as e:
|
||||
results.append({
|
||||
'engine': 'Bing',
|
||||
'status': 'error',
|
||||
'message': f'请求失败: {str(e)}'
|
||||
})
|
||||
|
||||
# 统计成功数量
|
||||
success_count = sum(1 for r in results if r['status'] == 'success')
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': f'已通知 {success_count}/{len(results)} 个搜索引擎',
|
||||
'sitemap_url': sitemap_url,
|
||||
'results': results
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'通知失败: {str(e)}'
|
||||
}), 500
|
||||
|
||||
@app.route('/api/refresh-site-news/<site_code>', methods=['POST'])
|
||||
def refresh_site_news(site_code):
|
||||
"""手动刷新指定网站的新闻(前台用户可访问)- v2.3新增"""
|
||||
|
||||
@@ -79,6 +79,12 @@
|
||||
<div class="nav-section">
|
||||
<div class="nav-section-title">系统</div>
|
||||
<ul class="nav-menu">
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('seo_tools') }}" class="nav-link">
|
||||
<span class="material-symbols-outlined nav-icon">search</span>
|
||||
<span class="nav-text">SEO工具</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('batch_import') }}" class="nav-link">
|
||||
<span class="material-symbols-outlined nav-icon">upload_file</span>
|
||||
|
||||
416
templates/admin/seo_tools.html
Normal file
416
templates/admin/seo_tools.html
Normal file
@@ -0,0 +1,416 @@
|
||||
{% extends 'admin/master.html' %}
|
||||
|
||||
{% block head_css %}
|
||||
<!-- Font Awesome for icons -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1 class="mb-4">
|
||||
<i class="fa fa-search"></i> SEO工具管理
|
||||
</h1>
|
||||
|
||||
<!-- Sitemap状态卡片 -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="fa fa-sitemap"></i> Sitemap状态
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if sitemap_info.exists %}
|
||||
<div class="alert alert-success">
|
||||
<i class="fa fa-check-circle"></i> 静态sitemap.xml已生成
|
||||
</div>
|
||||
<table class="table table-sm">
|
||||
<tr>
|
||||
<th width="40%">最后更新时间:</th>
|
||||
<td>{{ sitemap_info.last_updated }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>文件大小:</th>
|
||||
<td>{{ (sitemap_info.size / 1024) | round(2) }} KB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>文件路径:</th>
|
||||
<td><code>static/sitemap.xml</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="alert alert-warning">
|
||||
<i class="fa fa-exclamation-triangle"></i> 静态sitemap.xml尚未生成
|
||||
</div>
|
||||
<p class="text-muted mb-0">点击下方按钮生成静态sitemap文件</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="fa fa-globe"></i> 动态Sitemap
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>动态sitemap路由始终可用:</p>
|
||||
<div class="input-group mb-3">
|
||||
<input type="text" class="form-control" value="{{ request.url_root }}sitemap.xml" readonly>
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="copyToClipboard('{{ request.url_root }}sitemap.xml')">
|
||||
<i class="fa fa-copy"></i> 复制
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-muted small mb-0">
|
||||
<i class="fa fa-info-circle"></i> 动态sitemap实时反映数据库内容,无需手动生成
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮区 -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-dark text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="fa fa-tools"></i> 快速操作
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6><i class="fa fa-file-code"></i> 生成静态Sitemap</h6>
|
||||
<p class="text-muted small">生成static/sitemap.xml文件,可用于静态服务或下载</p>
|
||||
<button id="generateSitemapBtn" class="btn btn-success btn-lg w-100">
|
||||
<i class="fa fa-cog"></i> 生成静态sitemap.xml
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6><i class="fa fa-bell"></i> 通知搜索引擎</h6>
|
||||
<p class="text-muted small">向Google、Baidu、Bing提交sitemap更新通知</p>
|
||||
<button id="notifyEnginesBtn" class="btn btn-primary btn-lg w-100">
|
||||
<i class="fa fa-paper-plane"></i> 通知搜索引擎更新
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-md-12">
|
||||
<button id="doAllBtn" class="btn btn-warning btn-lg w-100">
|
||||
<i class="fa fa-rocket"></i> 一键生成并通知(推荐)
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作结果显示区 -->
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="resultArea" class="card" style="display: none;">
|
||||
<div class="card-header bg-secondary text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="fa fa-history"></i> 操作结果
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body" id="resultContent">
|
||||
<!-- 动态填充内容 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.card {
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.btn-lg {
|
||||
padding: 12px 24px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#resultArea {
|
||||
animation: slideDown 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.result-item {
|
||||
padding: 12px;
|
||||
border-left: 4px solid #ddd;
|
||||
margin-bottom: 10px;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.result-item.success {
|
||||
border-left-color: #28a745;
|
||||
background: #d4edda;
|
||||
}
|
||||
|
||||
.result-item.error {
|
||||
border-left-color: #dc3545;
|
||||
background: #f8d7da;
|
||||
}
|
||||
|
||||
.result-item.warning {
|
||||
border-left-color: #ffc107;
|
||||
background: #fff3cd;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// 复制到剪贴板
|
||||
function copyToClipboard(text) {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
alert('已复制到剪贴板!');
|
||||
});
|
||||
}
|
||||
|
||||
// 禁用按钮
|
||||
function disableButtons() {
|
||||
document.querySelectorAll('#generateSitemapBtn, #notifyEnginesBtn, #doAllBtn').forEach(btn => {
|
||||
btn.disabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
// 启用按钮
|
||||
function enableButtons() {
|
||||
document.querySelectorAll('#generateSitemapBtn, #notifyEnginesBtn, #doAllBtn').forEach(btn => {
|
||||
btn.disabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
// 显示结果
|
||||
function showResult(html) {
|
||||
const resultArea = document.getElementById('resultArea');
|
||||
const resultContent = document.getElementById('resultContent');
|
||||
resultContent.innerHTML = html;
|
||||
resultArea.style.display = 'block';
|
||||
resultArea.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}
|
||||
|
||||
// 生成静态sitemap
|
||||
document.getElementById('generateSitemapBtn').addEventListener('click', async function() {
|
||||
disableButtons();
|
||||
const originalText = this.innerHTML;
|
||||
this.innerHTML = '<i class="fa fa-spinner fa-spin"></i> 生成中...';
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/generate-static-sitemap', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
showResult(`
|
||||
<div class="result-item success">
|
||||
<h5><i class="fa fa-check-circle"></i> 生成成功</h5>
|
||||
<p>${data.message}</p>
|
||||
<table class="table table-sm mt-2">
|
||||
<tr><th>URL数量:</th><td>${data.total_urls}</td></tr>
|
||||
<tr><th>文件路径:</th><td><code>${data.file_path}</code></td></tr>
|
||||
<tr><th>生成时间:</th><td>${data.timestamp}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
`);
|
||||
// 刷新页面以更新sitemap状态
|
||||
setTimeout(() => location.reload(), 2000);
|
||||
} else {
|
||||
showResult(`
|
||||
<div class="result-item error">
|
||||
<h5><i class="fa fa-times-circle"></i> 生成失败</h5>
|
||||
<p>${data.message}</p>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
} catch (error) {
|
||||
showResult(`
|
||||
<div class="result-item error">
|
||||
<h5><i class="fa fa-times-circle"></i> 请求失败</h5>
|
||||
<p>网络错误: ${error.message}</p>
|
||||
</div>
|
||||
`);
|
||||
} finally {
|
||||
this.innerHTML = originalText;
|
||||
enableButtons();
|
||||
}
|
||||
});
|
||||
|
||||
// 通知搜索引擎
|
||||
document.getElementById('notifyEnginesBtn').addEventListener('click', async function() {
|
||||
disableButtons();
|
||||
const originalText = this.innerHTML;
|
||||
this.innerHTML = '<i class="fa fa-spinner fa-spin"></i> 通知中...';
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/notify-search-engines', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
let resultsHtml = `
|
||||
<div class="result-item success">
|
||||
<h5><i class="fa fa-check-circle"></i> ${data.message}</h5>
|
||||
<p>Sitemap URL: <code>${data.sitemap_url}</code></p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
data.results.forEach(result => {
|
||||
const statusClass = result.status === 'success' ? 'success' : 'error';
|
||||
const icon = result.status === 'success' ? 'fa-check-circle' : 'fa-exclamation-circle';
|
||||
resultsHtml += `
|
||||
<div class="result-item ${statusClass}">
|
||||
<h6><i class="fa ${icon}"></i> ${result.engine}</h6>
|
||||
<p>${result.message}</p>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
showResult(resultsHtml);
|
||||
} else {
|
||||
showResult(`
|
||||
<div class="result-item error">
|
||||
<h5><i class="fa fa-times-circle"></i> 通知失败</h5>
|
||||
<p>${data.message}</p>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
} catch (error) {
|
||||
showResult(`
|
||||
<div class="result-item error">
|
||||
<h5><i class="fa fa-times-circle"></i> 请求失败</h5>
|
||||
<p>网络错误: ${error.message}</p>
|
||||
</div>
|
||||
`);
|
||||
} finally {
|
||||
this.innerHTML = originalText;
|
||||
enableButtons();
|
||||
}
|
||||
});
|
||||
|
||||
// 一键生成并通知
|
||||
document.getElementById('doAllBtn').addEventListener('click', async function() {
|
||||
disableButtons();
|
||||
const originalText = this.innerHTML;
|
||||
this.innerHTML = '<i class="fa fa-spinner fa-spin"></i> 处理中...';
|
||||
|
||||
let allResultsHtml = '';
|
||||
|
||||
try {
|
||||
// Step 1: 生成sitemap
|
||||
const sitemapResponse = await fetch('/api/generate-static-sitemap', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
const sitemapData = await sitemapResponse.json();
|
||||
|
||||
if (sitemapData.success) {
|
||||
allResultsHtml += `
|
||||
<div class="result-item success">
|
||||
<h5><i class="fa fa-check-circle"></i> 步骤1:生成sitemap成功</h5>
|
||||
<p>${sitemapData.message}</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Step 2: 通知搜索引擎
|
||||
const notifyResponse = await fetch('/api/notify-search-engines', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
const notifyData = await notifyResponse.json();
|
||||
|
||||
if (notifyData.success) {
|
||||
allResultsHtml += `
|
||||
<div class="result-item success">
|
||||
<h5><i class="fa fa-check-circle"></i> 步骤2:${notifyData.message}</h5>
|
||||
</div>
|
||||
`;
|
||||
|
||||
notifyData.results.forEach(result => {
|
||||
const statusClass = result.status === 'success' ? 'success' : 'warning';
|
||||
const icon = result.status === 'success' ? 'fa-check-circle' : 'fa-exclamation-circle';
|
||||
allResultsHtml += `
|
||||
<div class="result-item ${statusClass}">
|
||||
<h6><i class="fa ${icon}"></i> ${result.engine}</h6>
|
||||
<p>${result.message}</p>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
} else {
|
||||
allResultsHtml += `
|
||||
<div class="result-item error">
|
||||
<h5><i class="fa fa-times-circle"></i> 步骤2:通知搜索引擎失败</h5>
|
||||
<p>${notifyData.message}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
} else {
|
||||
allResultsHtml += `
|
||||
<div class="result-item error">
|
||||
<h5><i class="fa fa-times-circle"></i> 步骤1:生成sitemap失败</h5>
|
||||
<p>${sitemapData.message}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
showResult(allResultsHtml);
|
||||
|
||||
// 如果全部成功,2秒后刷新页面
|
||||
if (sitemapData.success) {
|
||||
setTimeout(() => location.reload(), 3000);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
showResult(`
|
||||
<div class="result-item error">
|
||||
<h5><i class="fa fa-times-circle"></i> 操作失败</h5>
|
||||
<p>网络错误: ${error.message}</p>
|
||||
</div>
|
||||
`);
|
||||
} finally {
|
||||
this.innerHTML = originalText;
|
||||
enableButtons();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user