From 30b1ef75d655f962da385ad8630e06562a8b5bdf Mon Sep 17 00:00:00 2001
From: Jowe <123822645+Selei1983@users.noreply.github.com>
Date: Tue, 30 Dec 2025 00:45:39 +0800
Subject: [PATCH] =?UTF-8?q?release:=20v2.1=20-=20Prompt=E7=AE=A1=E7=90=86?=
 =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E3=80=81=E9=A1=B5=E8=84=9A=E4=BC=98=E5=8C=96?=
 =?UTF-8?q?=E3=80=81=E5=9B=BE=E6=A0=87=E4=BF=AE=E5=A4=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

新增功能：
- Prompt管理：后台新增Prompt模板管理功能
- 数据库迁移：新增prompt_templates表及默认数据
- 页脚优化：添加ICP备案号(浙ICP备2025154782号-1)和Microsoft Clarity统计
- 图标修复：详情页Material Icons替换为Emoji
- 标签显示：修复编辑页标签名称无法显示的问题

技术改进：
- 添加正则表达式提取标签名称
- 优化页脚样式和链接
- 完善增量部署文档

🚀 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---
 INCREMENTAL_DEPLOY.md            | 208 ++++++++++++
 app.py                           | 313 +++++++++++++++++-
 export_data.py                   |  58 ++++
 migrate_db.py                    |  49 +++
 migrate_prompts.py               | 141 +++++++++
 models.py                        |  32 ++
 templates/admin/site/create.html | 455 ++++++++++++++++++++++++++-
 templates/admin/site/edit.html   | 522 +++++++++++++++++++++++++++++--
 templates/base_new.html          |  40 ++-
 templates/detail_new.html        | 165 ++++++++--
 10 files changed, 1887 insertions(+), 96 deletions(-)
 create mode 100644 INCREMENTAL_DEPLOY.md
 create mode 100644 export_data.py
 create mode 100644 migrate_db.py
 create mode 100644 migrate_prompts.py

diff --git a/INCREMENTAL_DEPLOY.md b/INCREMENTAL_DEPLOY.md
new file mode 100644
index 0000000..dc18d04
--- /dev/null
+++ b/INCREMENTAL_DEPLOY.md
@@ -0,0 +1,208 @@
+# ZJPB v2.1 增量部署指南
+
+## 📋 本次更新内容
+
+### 新增功能
+1. **Prompt管理系统** - 后台可管理AI提示词模板
+2. **详情页图标优化** - Material Icons替换为Emoji
+3. **标签显示修复** - 修复编辑页标签名称无法显示问题
+4. **页脚优化** - 添加ICP备案号和Microsoft Clarity统计
+
+### 数据库变更
+- 新增表：`prompt_templates` （Prompt模板表）
+- 无现有表结构变更，完全兼容旧数据
+
+---
+
+## 🔒 增量部署步骤
+
+### 第一步：备份生产数据库（必须！）
+
+在1Panel中备份数据库：
+```bash
+# 方法1：使用1Panel面板
+1. 进入1Panel -> 数据库
+2. 找到 ai_nav 数据库
+3. 点击"备份"按钮
+4. 下载备份文件到本地保存
+
+# 方法2：使用命令行
+mysqldump -h 112.124.42.38 -u ai_nav_user -p ai_nav > backup_$(date +%Y%m%d_%H%M%S).sql
+```
+
+### 第二步：停止生产应用
+
+```bash
+# SSH登录到生产服务器
+ssh root@your-server-ip
+
+# 进入应用目录
+cd /www/wwwroot/zjpb
+
+# 停止应用
+./manage.sh stop
+```
+
+### 第三步：备份现有代码
+
+```bash
+# 创建备份目录
+cd /www/wwwroot
+cp -r zjpb zjpb_backup_$(date +%Y%m%d_%H%M%S)
+```
+
+### 第四步：上传新代码
+
+**方法1：使用Git（推荐）**
+
+```bash
+# 在本地提交所有修改
+git add .
+git commit -m "release: v2.1 - Prompt管理系统、页脚优化、图标修复"
+git push origin master
+
+# 在服务器上拉取
+cd /www/wwwroot/zjpb
+git pull origin master
+```
+
+**方法2：手动上传**
+
+```bash
+# 在本地压缩（排除不需要的文件）
+zip -r zjpb_v2.1.zip . -x "*.pyc" "*__pycache__*" "*.git*" ".env" "venv/*" "test_*.py" "*.db" "nul"
+
+# 上传到服务器 /www/wwwroot/zjpb_new.zip
+# 然后解压覆盖
+cd /www/wwwroot/zjpb
+unzip -o ../zjpb_new.zip
+```
+
+### 第五步：安装新依赖（如有）
+
+```bash
+cd /www/wwwroot/zjpb
+source venv/bin/activate
+pip install -r requirements.txt
+```
+
+### 第六步：运行数据库迁移
+
+```bash
+# 激活虚拟环境
+source venv/bin/activate
+
+# 运行迁移脚本（创建 prompt_templates 表）
+python migrate_prompts.py
+```
+
+**预期输出：**
+```
+正在创建 prompt_templates 表...
+[OK] 表创建成功
+正在初始化默认prompt模板...
+[OK] 默认prompt模板初始化成功
+  - 标签生成: 1
+  - 主要功能生成: 2
+  - 详细介绍生成: 3
+```
+
+### 第七步：重启应用
+
+```bash
+./manage.sh start
+```
+
+### 第八步：验证部署
+
+**检查项：**
+
+1. **访问前台首页**
+   - 检查页脚是否显示ICP备案号
+   - 检查Clarity统计是否加载（F12查看Network）
+
+2. **访问详情页**
+   - 检查图标是否正常显示（不是Material Icons文本）
+
+3. **登录后台**
+   - 检查是否有"Prompt管理"菜单
+   - 进入Prompt管理，查看是否有3条默认数据
+
+4. **测试网站编辑**
+   - 编辑任意网站，检查标签是否正常显示（不是空白蓝框）
+
+5. **测试AI功能**
+   - 创建新网站，测试"AI生成标签"功能
+   - 测试"AI生成详细介绍"功能
+   - 测试"AI生成主要功能"功能
+
+---
+
+## 🔄 回滚方案（如出现问题）
+
+### 快速回滚代码
+
+```bash
+cd /www/wwwroot
+./zjpb/manage.sh stop
+
+# 删除新版本
+rm -rf zjpb
+
+# 恢复备份
+mv zjpb_backup_YYYYMMDD_HHMMSS zjpb
+
+# 重启
+cd zjpb
+./manage.sh start
+```
+
+### 恢复数据库
+
+```bash
+# 如果新表导致问题，可以删除新表
+mysql -h 112.124.42.38 -u ai_nav_user -p ai_nav
+
+# 在MySQL中执行
+DROP TABLE IF EXISTS prompt_templates;
+```
+
+---
+
+## 📝 注意事项
+
+1. ✅ **本次更新不会影响现有数据** - 只是新增表，不修改现有表
+2. ✅ **完全向后兼容** - 即使不运行迁移脚本，前台也能正常访问
+3. ✅ **可以随时回滚** - 保留了完整备份
+4. ⚠️ **必须备份数据库** - 虽然风险很低，但备份是必须的
+5. ⚠️ **检查.env配置** - 确保生产环境的.env配置正确
+
+---
+
+## 🐛 常见问题
+
+### Q1: 迁移脚本报错 "表已存在"
+**A:** 说明之前已经运行过迁移，可以跳过此步骤
+
+### Q2: Prompt管理菜单看不到
+**A:** 清除浏览器缓存，重新登录后台
+
+### Q3: 标签还是显示不出来
+**A:** 清除浏览器缓存，强制刷新（Ctrl+F5）
+
+### Q4: Clarity统计没加载
+**A:** 检查网络是否能访问 clarity.ms，可能被墙
+
+---
+
+## 📞 技术支持
+
+如遇问题，请检查日志：
+
+```bash
+# 查看应用日志
+./manage.sh logs
+
+# 查看错误日志
+tail -f logs/error.log
+```
diff --git a/app.py b/app.py
index 14288f1..7a2e392 100644
--- a/app.py
+++ b/app.py
@@ -1,11 +1,12 @@
 import os
+import markdown
 from flask import Flask, render_template, redirect, url_for, request, flash, jsonify
 from flask_login import LoginManager, login_user, logout_user, login_required, current_user
 from flask_admin import Admin, AdminIndexView, expose
 from flask_admin.contrib.sqla import ModelView
 from datetime import datetime
 from config import config
-from models import db, Site, Tag, Admin as AdminModel, News
+from models import db, Site, Tag, Admin as AdminModel, News, site_tags, PromptTemplate
 from utils.website_fetcher import WebsiteFetcher
 from utils.tag_generator import TagGenerator
 
@@ -19,6 +20,14 @@ def create_app(config_name='default'):
     # 初始化数据库
     db.init_app(app)
 
+    # 添加Markdown过滤器
+    @app.template_filter('markdown')
+    def markdown_filter(text):
+        """将Markdown文本转换为HTML"""
+        if not text:
+            return ''
+        return markdown.markdown(text, extensions=['nl2br', 'fenced_code'])
+
     # 初始化登录管理
     login_manager = LoginManager()
     login_manager.init_app(app)
@@ -36,6 +45,22 @@ def create_app(config_name='default'):
         # 获取所有启用的标签
         tags = Tag.query.order_by(Tag.sort_order.desc(), Tag.id).all()
 
+        # 优化：使用一次SQL查询统计所有标签的网站数量
+        tag_counts = {}
+        if tags:
+            # 使用JOIN查询一次性获取所有标签的网站数量
+            from sqlalchemy import func
+            counts_query = db.session.query(
+                site_tags.c.tag_id,
+                func.count(site_tags.c.site_id).label('count')
+            ).join(
+                Site, site_tags.c.site_id == Site.id
+            ).filter(
+                Site.is_active == True
+            ).group_by(site_tags.c.tag_id).all()
+
+            tag_counts = {tag_id: count for tag_id, count in counts_query}
+
         # 获取筛选参数
         tag_slug = request.args.get('tag')
         search_query = request.args.get('q', '').strip()
@@ -57,7 +82,7 @@ def create_app(config_name='default'):
                 pagination = None
                 return render_template('index_new.html', sites=sites, tags=tags,
                                      selected_tag=selected_tag, search_query=search_query,
-                                     pagination=pagination)
+                                     pagination=pagination, tag_counts=tag_counts)
 
         # 搜索功能
         if search_query:
@@ -79,7 +104,7 @@ def create_app(config_name='default'):
 
         return render_template('index_new.html', sites=sites, tags=tags,
                              selected_tag=selected_tag, search_query=search_query,
-                             pagination=pagination)
+                             pagination=pagination, tag_counts=tag_counts)
 
     @app.route('/site/<code>')
     def site_detail(code):
@@ -138,6 +163,51 @@ def create_app(config_name='default'):
         logout_user()
         return redirect(url_for('index'))
 
+    @app.route('/admin/change-password', methods=['GET', 'POST'])
+    @login_required
+    def change_password():
+        """修改密码"""
+        if request.method == 'POST':
+            old_password = request.form.get('old_password', '').strip()
+            new_password = request.form.get('new_password', '').strip()
+            confirm_password = request.form.get('confirm_password', '').strip()
+
+            # 验证旧密码
+            if not current_user.check_password(old_password):
+                flash('旧密码错误', 'error')
+                return render_template('admin/change_password.html')
+
+            # 验证新密码
+            if not new_password:
+                flash('新密码不能为空', 'error')
+                return render_template('admin/change_password.html')
+
+            if len(new_password) < 6:
+                flash('新密码长度至少6位', 'error')
+                return render_template('admin/change_password.html')
+
+            if new_password != confirm_password:
+                flash('两次输入的新密码不一致', 'error')
+                return render_template('admin/change_password.html')
+
+            if old_password == new_password:
+                flash('新密码不能与旧密码相同', 'error')
+                return render_template('admin/change_password.html')
+
+            # 修改密码
+            try:
+                current_user.set_password(new_password)
+                db.session.commit()
+                flash('密码修改成功，请重新登录', 'success')
+                logout_user()
+                return redirect(url_for('admin_login'))
+            except Exception as e:
+                db.session.rollback()
+                flash(f'密码修改失败：{str(e)}', 'error')
+                return render_template('admin/change_password.html')
+
+        return render_template('admin/change_password.html')
+
     # ========== API路由 ==========
     @app.route('/api/fetch-website-info', methods=['POST'])
     @login_required
@@ -165,17 +235,18 @@ def create_app(config_name='default'):
                     'message': '无法获取网站信息，请检查URL是否正确或手动填写'
                 })
 
-            # 下载Logo（如果有）
+            # 下载Logo到本地（如果有）
             logo_path = None
             if info.get('logo_url'):
-                logo_path = fetcher.download_logo(info['logo_url'])
+                logo_path = fetcher.download_logo(info['logo_url'], save_dir='static/logos')
 
+            # 如果下载失败，不返回远程URL，让用户手动上传
             return jsonify({
                 'success': True,
                 'data': {
                     'name': info.get('name', ''),
                     'description': info.get('description', ''),
-                    'logo': logo_path or info.get('logo_url', '')
+                    'logo': logo_path if logo_path else ''
                 }
             })
 
@@ -185,6 +256,148 @@ def create_app(config_name='default'):
                 'message': f'抓取失败: {str(e)}'
             }), 500
 
+    @app.route('/api/upload-logo', methods=['POST'])
+    @login_required
+    def upload_logo():
+        """上传Logo图片API"""
+        try:
+            # 检查文件是否存在
+            if 'logo' not in request.files:
+                return jsonify({
+                    'success': False,
+                    'message': '请选择要上传的图片'
+                }), 400
+
+            file = request.files['logo']
+
+            # 检查文件名
+            if file.filename == '':
+                return jsonify({
+                    'success': False,
+                    'message': '未选择文件'
+                }), 400
+
+            # 检查文件类型
+            allowed_extensions = {'png', 'jpg', 'jpeg', 'gif', 'svg', 'ico', 'webp'}
+            filename = file.filename.lower()
+            if not any(filename.endswith('.' + ext) for ext in allowed_extensions):
+                return jsonify({
+                    'success': False,
+                    'message': '不支持的文件格式，请上传图片文件(png, jpg, gif, svg, ico, webp)'
+                }), 400
+
+            # 创建保存目录
+            save_dir = 'static/logos'
+            os.makedirs(save_dir, exist_ok=True)
+
+            # 生成安全的文件名
+            import time
+            import hashlib
+            ext = os.path.splitext(filename)[1]
+            timestamp = str(int(time.time() * 1000))
+            hash_name = hashlib.md5(f"{filename}{timestamp}".encode()).hexdigest()[:16]
+            safe_filename = f"logo_{hash_name}{ext}"
+            filepath = os.path.join(save_dir, safe_filename)
+
+            # 保存文件
+            file.save(filepath)
+
+            # 返回相对路径
+            return jsonify({
+                'success': True,
+                'path': f'/{filepath.replace(os.sep, "/")}'
+            })
+
+        except Exception as e:
+            return jsonify({
+                'success': False,
+                'message': f'上传失败: {str(e)}'
+            }), 500
+
+    @app.route('/api/generate-features', methods=['POST'])
+    @login_required
+    def generate_features():
+        """使用DeepSeek自动生成网站主要功能"""
+        try:
+            data = request.get_json()
+            name = data.get('name', '').strip()
+            description = data.get('description', '').strip()
+            url = data.get('url', '').strip()
+
+            if not name or not description:
+                return jsonify({
+                    'success': False,
+                    'message': '请提供网站名称和描述'
+                }), 400
+
+            # 生成功能列表
+            generator = TagGenerator()
+            features = generator.generate_features(name, description, url)
+
+            if not features:
+                return jsonify({
+                    'success': False,
+                    'message': 'DeepSeek功能生成失败，请检查API配置'
+                }), 500
+
+            return jsonify({
+                'success': True,
+                'features': features
+            })
+
+        except ValueError as e:
+            return jsonify({
+                'success': False,
+                'message': str(e)
+            }), 400
+        except Exception as e:
+            return jsonify({
+                'success': False,
+                'message': f'生成失败: {str(e)}'
+            }), 500
+
+    @app.route('/api/generate-description', methods=['POST'])
+    @login_required
+    def generate_description():
+        """使用DeepSeek自动生成网站详细介绍"""
+        try:
+            data = request.get_json()
+            name = data.get('name', '').strip()
+            short_desc = data.get('short_desc', '').strip()
+            url = data.get('url', '').strip()
+
+            if not name:
+                return jsonify({
+                    'success': False,
+                    'message': '请提供网站名称'
+                }), 400
+
+            # 生成详细介绍
+            generator = TagGenerator()
+            description = generator.generate_description(name, short_desc, url)
+
+            if not description:
+                return jsonify({
+                    'success': False,
+                    'message': 'DeepSeek详细介绍生成失败，请检查API配置'
+                }), 500
+
+            return jsonify({
+                'success': True,
+                'description': description
+            })
+
+        except ValueError as e:
+            return jsonify({
+                'success': False,
+                'message': str(e)
+            }), 400
+        except Exception as e:
+            return jsonify({
+                'success': False,
+                'message': f'生成失败: {str(e)}'
+            }), 500
+
     @app.route('/api/generate-tags', methods=['POST'])
     @login_required
     def generate_tags():
@@ -345,11 +558,11 @@ def create_app(config_name='default'):
                                     })
                                     continue
 
-                        # 4. 下载Logo（失败不影响导入）
+                        # 4. 下载Logo到本地（失败不影响导入）
                         logo_path = None
                         if info.get('logo_url'):
                             try:
-                                logo_path = fetcher.download_logo(info['logo_url'])
+                                logo_path = fetcher.download_logo(info['logo_url'], save_dir='static/logos')
                             except Exception as e:
                                 print(f"下载Logo失败 ({url}): {str(e)}")
                                 # Logo下载失败不影响网站导入
@@ -544,9 +757,47 @@ def create_app(config_name='default'):
             import re
             import random
             from pypinyin import lazy_pinyin
+            from flask import request
 
             # 使用no_autoflush防止在查询时触发提前flush
             with db.session.no_autoflush:
+                # 处理手动输入的新标签
+                new_tags_str = request.form.get('new_tags', '')
+                if new_tags_str:
+                    new_tag_names = [name.strip() for name in new_tags_str.split(',') if name.strip()]
+                    for tag_name in new_tag_names:
+                        # 检查标签是否已存在
+                        existing_tag = Tag.query.filter_by(name=tag_name).first()
+                        if not existing_tag:
+                            # 创建新标签
+                            tag_slug = ''.join(lazy_pinyin(tag_name))
+                            tag_slug = tag_slug.lower()
+                            tag_slug = re.sub(r'[^\w\s-]', '', tag_slug)
+                            tag_slug = re.sub(r'[-\s]+', '-', tag_slug).strip('-')
+
+                            # 确保slug唯一
+                            base_tag_slug = tag_slug[:50]
+                            counter = 1
+                            final_tag_slug = tag_slug
+                            while Tag.query.filter_by(slug=final_tag_slug).first():
+                                final_tag_slug = f"{base_tag_slug}-{counter}"
+                                counter += 1
+                                if counter > 100:
+                                    final_tag_slug = f"{base_tag_slug}-{random.randint(1000, 9999)}"
+                                    break
+
+                            new_tag = Tag(name=tag_name, slug=final_tag_slug)
+                            db.session.add(new_tag)
+                            db.session.flush()  # 确保新标签有ID
+
+                            # 添加到模型的标签列表
+                            if new_tag not in model.tags:
+                                model.tags.append(new_tag)
+                        else:
+                            # 添加已存在的标签
+                            if existing_tag not in model.tags:
+                                model.tags.append(existing_tag)
+
                 # 如果code为空，自动生成唯一的8位数字编码
                 if not model.code or model.code.strip() == '':
                     max_attempts = 10
@@ -684,6 +935,51 @@ def create_app(config_name='default'):
             ]
         }
 
+    # Prompt模板管理视图
+    class PromptAdmin(SecureModelView):
+        can_edit = True
+        can_delete = False  # 不允许删除，避免系统必需的prompt被删除
+        can_create = True
+        can_view_details = False
+
+        # 显示操作列
+        column_display_actions = True
+
+        column_list = ['id', 'key', 'name', 'description', 'is_active', 'updated_at']
+        column_searchable_list = ['key', 'name', 'description']
+        column_filters = ['is_active', 'key']
+        column_labels = {
+            'id': 'ID',
+            'key': '唯一标识',
+            'name': '模板名称',
+            'system_prompt': '系统提示词',
+            'user_prompt_template': '用户提示词模板',
+            'description': '模板说明',
+            'is_active': '是否启用',
+            'created_at': '创建时间',
+            'updated_at': '更新时间'
+        }
+        form_columns = ['key', 'name', 'description', 'system_prompt', 'user_prompt_template', 'is_active']
+
+        # 字段说明
+        column_descriptions = {
+            'key': '唯一标识，如: tags, features, description',
+            'system_prompt': 'AI的系统角色设定',
+            'user_prompt_template': '用户提示词模板，支持变量如 {name}, {description}, {url}',
+        }
+
+        # 表单字段配置
+        form_widget_args = {
+            'system_prompt': {
+                'rows': 3,
+                'style': 'font-family: monospace;'
+            },
+            'user_prompt_template': {
+                'rows': 20,
+                'style': 'font-family: monospace;'
+            }
+        }
+
     # 初始化 Flask-Admin
     admin = Admin(
         app,
@@ -696,6 +992,7 @@ def create_app(config_name='default'):
     admin.add_view(SiteAdmin(Site, db.session, name='网站管理'))
     admin.add_view(TagAdmin(Tag, db.session, name='标签管理'))
     admin.add_view(NewsAdmin(News, db.session, name='新闻管理'))
+    admin.add_view(PromptAdmin(PromptTemplate, db.session, name='Prompt管理'))
     admin.add_view(AdminAdmin(AdminModel, db.session, name='管理员', endpoint='admin_users'))
 
     return app
diff --git a/export_data.py b/export_data.py
new file mode 100644
index 0000000..df212a9
--- /dev/null
+++ b/export_data.py
@@ -0,0 +1,58 @@
+# -*- coding: utf-8 -*-
+"""
+数据导出脚本
+导出现有数据到SQL文件
+"""
+import subprocess
+import os
+from datetime import datetime
+
+def export_database():
+    """导出数据库到SQL文件"""
+    # 从.env读取数据库配置
+    from dotenv import load_dotenv
+    load_dotenv()
+
+    db_host = os.getenv('DB_HOST', 'localhost')
+    db_port = os.getenv('DB_PORT', '3306')
+    db_user = os.getenv('DB_USER')
+    db_password = os.getenv('DB_PASSWORD')
+    db_name = os.getenv('DB_NAME')
+
+    # 生成备份文件名
+    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
+    backup_file = f'backup_{db_name}_{timestamp}.sql'
+
+    # mysqldump命令
+    cmd = [
+        'mysqldump',
+        '-h', db_host,
+        '-P', db_port,
+        '-u', db_user,
+        f'-p{db_password}',
+        '--single-transaction',
+        '--routines',
+        '--triggers',
+        db_name
+    ]
+
+    print(f"正在导出数据库 {db_name} ...")
+
+    try:
+        with open(backup_file, 'w', encoding='utf-8') as f:
+            subprocess.run(cmd, stdout=f, stderr=subprocess.PIPE, check=True)
+
+        file_size = os.path.getsize(backup_file) / 1024  # KB
+        print(f"✓ 数据库导出成功！")
+        print(f"  文件: {backup_file}")
+        print(f"  大小: {file_size:.2f} KB")
+        print(f"\n请将此文件上传到服务器进行恢复")
+
+    except subprocess.CalledProcessError as e:
+        print(f"✗ 导出失败: {e.stderr.decode()}")
+    except FileNotFoundError:
+        print("✗ 错误: 找不到 mysqldump 命令")
+        print("  请确保MySQL客户端工具已安装并在PATH中")
+
+if __name__ == '__main__':
+    export_database()
diff --git a/migrate_db.py b/migrate_db.py
new file mode 100644
index 0000000..4d4bdef
--- /dev/null
+++ b/migrate_db.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+"""
+数据库安全迁移脚本
+只创建缺失的表，不删除现有数据
+用于生产环境部署
+"""
+
+import sys
+from app import create_app
+from models import db, Admin
+
+def migrate_database():
+    """安全迁移数据库（不删除数据）"""
+    app = create_app('production')
+
+    with app.app_context():
+        print("正在检查数据库表...")
+
+        # 只创建不存在的表（不会删除数据）
+        db.create_all()
+        print("✓ 数据库表检查完成")
+
+        # 检查是否存在管理员
+        admin_count = Admin.query.count()
+
+        if admin_count == 0:
+            print("\n未找到管理员账号，正在创建默认管理员...")
+            admin = Admin(
+                username='admin',
+                email='admin@example.com',
+                is_active=True
+            )
+            admin.set_password('admin123')
+            db.session.add(admin)
+            db.session.commit()
+
+            print("✓ 默认管理员创建成功")
+            print("  用户名: admin")
+            print("  密码: admin123")
+            print("\n⚠️  请立即登录后台修改密码！")
+        else:
+            print(f"\n✓ 已存在 {admin_count} 个管理员账号")
+
+        print("\n" + "="*50)
+        print("数据库迁移完成！")
+        print("="*50)
+
+if __name__ == '__main__':
+    migrate_database()
diff --git a/migrate_prompts.py b/migrate_prompts.py
new file mode 100644
index 0000000..a6bd693
--- /dev/null
+++ b/migrate_prompts.py
@@ -0,0 +1,141 @@
+"""创建 prompt_templates 表并初始化默认数据"""
+import os
+import sys
+from app import create_app
+from models import db, PromptTemplate
+
+# 设置输出编码为UTF-8
+if sys.platform.startswith('win'):
+    sys.stdout.reconfigure(encoding='utf-8')
+
+def migrate_prompts():
+    """创建表并初始化默认prompt模板"""
+    app = create_app(os.getenv('FLASK_ENV', 'development'))
+
+    with app.app_context():
+        # 创建表
+        print("正在创建 prompt_templates 表...")
+        db.create_all()
+        print("[OK] 表创建成功")
+
+        # 检查是否已有数据
+        existing_count = PromptTemplate.query.count()
+        if existing_count > 0:
+            print(f"[WARN] 表中已有 {existing_count} 条数据，跳过初始化")
+            return
+
+        # 初始化默认prompt模板
+        print("正在初始化默认prompt模板...")
+
+        # 1. 标签生成模板
+        tags_prompt = PromptTemplate(
+            key='tags',
+            name='标签生成',
+            description='根据网站名称和描述生成3-5个分类标签',
+            system_prompt='你是一个专业的AI工具分类专家，擅长为各类AI产品生成准确的标签。',
+            user_prompt_template='''你是一个AI工具导航网站的标签生成助手。根据以下产品信息，生成3-5个最合适的标签。
+
+产品名称: {name}
+
+产品描述: {description}
+{existing_tags}
+
+要求：
+1. 标签应该准确描述产品的功能、类型或应用场景
+2. 每个标签2-4个汉字
+3. 标签要具体且有区分度
+4. 如果是AI工具，可以标注具体的AI类型（如"GPT"、"图像生成"等）
+5. 只返回标签，用逗号分隔，不要其他说明
+
+示例输出格式：写作助手,营销,GPT,内容生成
+
+请生成标签：''',
+            is_active=True
+        )
+
+        # 2. 主要功能生成模板
+        features_prompt = PromptTemplate(
+            key='features',
+            name='主要功能生成',
+            description='根据网站名称和描述生成5-8个主要功能点',
+            system_prompt='你是一个专业的AI产品文案专家，擅长提炼产品核心功能和价值点。',
+            user_prompt_template='''你是一个AI工具导航网站的内容编辑助手。根据以下产品信息，生成详细的主要功能列表。
+
+产品名称: {name}
+
+产品描述: {description}
+{url_info}
+
+要求：
+1. 生成5-8个主要功能点
+2. 每个功能点要具体、清晰、有吸引力
+3. 使用Markdown无序列表格式（以"- "开头）
+4. 每个功能点一行，简洁有力（10-30字）
+5. 突出产品的核心价值和特色功能
+6. 使用专业但易懂的语言
+7. 不要添加任何标题或额外说明，直接输出功能列表
+
+示例输出格式：
+- 智能文本生成，支持多种写作场景
+- 实时语法检查和优化建议
+- 多语言翻译，准确率高达95%
+- 一键生成营销文案和广告语
+- 团队协作，支持多人同时编辑
+
+请生成功能列表：''',
+            is_active=True
+        )
+
+        # 3. 详细介绍生成模板
+        description_prompt = PromptTemplate(
+            key='description',
+            name='详细介绍生成',
+            description='根据网站名称和简短描述生成200-400字的详细介绍',
+            system_prompt='你是一个专业的AI产品文案专家，擅长撰写准确、客观、有吸引力的产品介绍。',
+            user_prompt_template='''你是一个AI工具导航网站的内容编辑助手。根据以下产品信息，生成详细、专业且吸引人的产品介绍。
+
+产品名称: {name}
+{short_desc_info}
+{url_info}
+
+要求：
+1. 生成200-400字的详细介绍
+2. 包含以下内容：
+   - 产品定位和核心价值（这是什么产品，解决什么问题）
+   - 主要特点和优势（为什么选择这个产品）
+   - 适用场景和目标用户（谁会用，用在哪里）
+3. 使用Markdown格式，可以包含：
+   - 段落分隔（空行）
+   - 加粗重点内容（**文字**）
+   - 列表（- 列表项）
+4. 语言专业但易懂，突出产品价值
+5. 不要添加标题，直接输出正文内容
+6. 语气客观、事实性强，避免过度营销
+
+示例输出格式：
+ChatGPT是由OpenAI开发的**先进对话式AI助手**，基于GPT-4大语言模型构建。它能够理解和生成自然语言，为用户提供智能对话、内容创作、代码编写等多种服务。
+
+**核心优势：**
+- 强大的语言理解和生成能力
+- 支持多轮对话，上下文连贯
+- 覆盖编程、写作、翻译等多个领域
+
+适用于内容创作者、程序员、学生等各类用户，可用于日常问答、文案撰写、学习辅导、编程助手等多种场景。
+
+请生成详细介绍：''',
+            is_active=True
+        )
+
+        # 添加到数据库
+        db.session.add(tags_prompt)
+        db.session.add(features_prompt)
+        db.session.add(description_prompt)
+        db.session.commit()
+
+        print("[OK] 默认prompt模板初始化成功")
+        print(f"  - 标签生成: {tags_prompt.id}")
+        print(f"  - 主要功能生成: {features_prompt.id}")
+        print(f"  - 详细介绍生成: {description_prompt.id}")
+
+if __name__ == '__main__':
+    migrate_prompts()
diff --git a/models.py b/models.py
index 57e988a..fae1c97 100644
--- a/models.py
+++ b/models.py
@@ -136,3 +136,35 @@ class Admin(UserMixin, db.Model):
 
     def __repr__(self):
         return f'<Admin {self.username}>'
+
+class PromptTemplate(db.Model):
+    """AI提示词模板模型"""
+    __tablename__ = 'prompt_templates'
+
+    id = db.Column(db.Integer, primary_key=True)
+    key = db.Column(db.String(50), unique=True, nullable=False, comment='唯一标识(tags/features/description)')
+    name = db.Column(db.String(100), nullable=False, comment='模板名称')
+    system_prompt = db.Column(db.Text, nullable=False, comment='系统提示词')
+    user_prompt_template = db.Column(db.Text, nullable=False, comment='用户提示词模板(支持变量)')
+    description = db.Column(db.String(200), comment='模板说明')
+    is_active = db.Column(db.Boolean, default=True, comment='是否启用')
+    created_at = db.Column(db.DateTime, default=datetime.now, comment='创建时间')
+    updated_at = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now, comment='更新时间')
+
+    def __repr__(self):
+        return f'<PromptTemplate {self.name}>'
+
+    def to_dict(self):
+        """转换为字典"""
+        return {
+            'id': self.id,
+            'key': self.key,
+            'name': self.name,
+            'system_prompt': self.system_prompt,
+            'user_prompt_template': self.user_prompt_template,
+            'description': self.description,
+            'is_active': self.is_active,
+            'created_at': self.created_at.strftime('%Y-%m-%d %H:%M:%S') if self.created_at else None,
+            'updated_at': self.updated_at.strftime('%Y-%m-%d %H:%M:%S') if self.updated_at else None
+        }
+
diff --git a/templates/admin/site/create.html b/templates/admin/site/create.html
index f32bed6..ed0597f 100644
--- a/templates/admin/site/create.html
+++ b/templates/admin/site/create.html
@@ -11,6 +11,28 @@
         margin-top: 10px;
         margin-bottom: 15px;
     }
+    .generate-features-btn {
+        margin-top: 10px;
+        margin-bottom: 15px;
+    }
+    .upload-logo-btn {
+        margin-top: 10px;
+        margin-bottom: 15px;
+    }
+    .logo-preview {
+        margin-top: 10px;
+        max-width: 200px;
+        max-height: 200px;
+        display: none;
+        border: 1px solid #ddd;
+        border-radius: 8px;
+        padding: 10px;
+    }
+    .logo-preview img {
+        max-width: 100%;
+        max-height: 150px;
+        object-fit: contain;
+    }
     .fetch-status {
         margin-top: 10px;
         padding: 10px;
@@ -47,6 +69,26 @@
         from { transform: rotate(0deg); }
         to { transform: rotate(360deg); }
     }
+    /* 标签输入框样式 */
+    .tag-input-wrapper {
+        margin-top: 10px;
+    }
+    .tag-input-field {
+        width: 100%;
+        padding: 8px 12px;
+        border: 1px solid #DCDFE6;
+        border-radius: 4px;
+        font-size: 14px;
+    }
+    .tag-input-field:focus {
+        outline: none;
+        border-color: #0052D9;
+    }
+    .tag-input-help {
+        margin-top: 5px;
+        font-size: 12px;
+        color: #606266;
+    }
 </style>
 
 <script>
@@ -130,9 +172,238 @@ document.addEventListener('DOMContentLoaded', function() {
         }
     }
 
-    // 在标签字段后添加"AI生成标签"按钮
-    const tagsField = document.querySelector('select[name="tags"]');
-    if (tagsField) {
+    // 在Logo字段后添加"上传Logo"功能
+    const logoField = document.querySelector('input[name="logo"]');
+    if (logoField) {
+        // 创建文件输入框
+        const fileInput = document.createElement('input');
+        fileInput.type = 'file';
+        fileInput.accept = 'image/*';
+        fileInput.style.display = 'none';
+
+        // 创建上传按钮
+        const uploadBtn = document.createElement('button');
+        uploadBtn.type = 'button';
+        uploadBtn.className = 'btn btn-warning upload-logo-btn';
+        uploadBtn.innerHTML = '📁 上传Logo图片';
+
+        // 创建预览容器
+        const previewDiv = document.createElement('div');
+        previewDiv.className = 'logo-preview';
+        previewDiv.innerHTML = '<img src="" alt="Logo预览"><p style="margin-top:5px; font-size:12px; color:#666;">Logo预览</p>';
+
+        logoField.parentNode.appendChild(fileInput);
+        logoField.parentNode.appendChild(uploadBtn);
+        logoField.parentNode.appendChild(previewDiv);
+
+        // 点击按钮触发文件选择
+        uploadBtn.addEventListener('click', function() {
+            fileInput.click();
+        });
+
+        // 文件选择后自动上传
+        fileInput.addEventListener('change', function() {
+            const file = fileInput.files[0];
+            if (!file) return;
+
+            // 验证文件类型
+            if (!file.type.startsWith('image/')) {
+                alert('请选择图片文件！');
+                return;
+            }
+
+            // 验证文件大小（限制5MB）
+            if (file.size > 5 * 1024 * 1024) {
+                alert('图片文件不能超过5MB！');
+                return;
+            }
+
+            // 上传文件
+            const formData = new FormData();
+            formData.append('logo', file);
+
+            uploadBtn.disabled = true;
+            uploadBtn.textContent = '上传中...';
+
+            fetch('/api/upload-logo', {
+                method: 'POST',
+                body: formData
+            })
+            .then(response => response.json())
+            .then(data => {
+                if (data.success) {
+                    // 设置Logo字段值
+                    logoField.value = data.path;
+
+                    // 显示预览
+                    const img = previewDiv.querySelector('img');
+                    img.src = data.path;
+                    previewDiv.style.display = 'block';
+
+                    alert('✓ Logo上传成功！');
+                } else {
+                    alert('✗ ' + (data.message || '上传失败'));
+                }
+            })
+            .catch(error => {
+                console.error('Error:', error);
+                alert('✗ 上传失败，请重试');
+            })
+            .finally(() => {
+                uploadBtn.disabled = false;
+                uploadBtn.innerHTML = '📁 上传Logo图片';
+                fileInput.value = '';
+            });
+        });
+
+        // 如果Logo字段有值，显示预览
+        if (logoField.value) {
+            const img = previewDiv.querySelector('img');
+            img.src = logoField.value;
+            previewDiv.style.display = 'block';
+        }
+
+        // 监听Logo字段变化，更新预览
+        logoField.addEventListener('input', function() {
+            if (logoField.value) {
+                const img = previewDiv.querySelector('img');
+                img.src = logoField.value;
+                previewDiv.style.display = 'block';
+            } else {
+                previewDiv.style.display = 'none';
+            }
+        });
+    }
+
+    // 处理标签字段 - 添加手动输入功能
+    const tagsSelect = document.querySelector('select[name="tags"]');
+    if (tagsSelect) {
+        // 隐藏原始的select字段
+        tagsSelect.style.display = 'none';
+
+        // 创建文本输入框
+        const tagInputWrapper = document.createElement('div');
+        tagInputWrapper.className = 'tag-input-wrapper';
+
+        const tagInput = document.createElement('input');
+        tagInput.type = 'text';
+        tagInput.className = 'tag-input-field';
+        tagInput.placeholder = '输入标签名称，按回车添加（如：AI工具、图像处理、免费）';
+
+        const tagHelpText = document.createElement('div');
+        tagHelpText.className = 'tag-input-help';
+        tagHelpText.textContent = '💡 提示：输入标签名称后按回车键添加，可以添加多个标签。已选标签会自动添加到下方列表。';
+
+        const selectedTagsDiv = document.createElement('div');
+        selectedTagsDiv.className = 'selected-tags';
+        selectedTagsDiv.style.marginTop = '10px';
+
+        tagInputWrapper.appendChild(tagInput);
+        tagInputWrapper.appendChild(tagHelpText);
+        tagInputWrapper.appendChild(selectedTagsDiv);
+        tagsSelect.parentNode.insertBefore(tagInputWrapper, tagsSelect.nextSibling);
+
+        // 显示已选标签
+        function updateSelectedTags() {
+            selectedTagsDiv.innerHTML = '';
+            const selectedOptions = Array.from(tagsSelect.selectedOptions);
+
+            // 如果没有选中的标签，显示提示
+            if (selectedOptions.length === 0) {
+                selectedTagsDiv.innerHTML = '<span style="color:#999; font-size:12px;">暂无已选标签</span>';
+                return;
+            }
+
+            selectedOptions.forEach(option => {
+                const tag = document.createElement('span');
+                tag.style.cssText = 'display:inline-block; background:#0052D9; color:white; padding:4px 10px; margin:4px; border-radius:4px; font-size:12px;';
+
+                // 获取标签文本 - 兼容多种方式
+                let tagText = option.textContent || option.innerText || option.text || option.innerHTML || option.label || `标签${option.value}`;
+
+                // 处理 <Tag XXX> 格式，提取出实际标签名称
+                const match = tagText.match(/<Tag\s+(.+?)>/);
+                if (match) {
+                    tagText = match[1];  // 提取标签名称
+                }
+
+                tag.innerHTML = tagText + ' <span style="cursor:pointer; margin-left:5px; font-weight:bold;" data-tag-id="' + option.value + '">×</span>';
+                selectedTagsDiv.appendChild(tag);
+
+                // 为删除按钮添加点击事件
+                const deleteBtn = tag.querySelector('span[data-tag-id]');
+                if (deleteBtn) {
+                    deleteBtn.addEventListener('click', function(e) {
+                        e.stopPropagation();
+                        option.selected = false;
+                        updateSelectedTags();
+                    });
+                }
+            });
+        }
+
+        // 添加标签
+        tagInput.addEventListener('keypress', function(e) {
+            if (e.key === 'Enter') {
+                e.preventDefault();
+                const tagName = tagInput.value.trim();
+
+                if (!tagName) {
+                    return;
+                }
+
+                // 检查标签是否已存在
+                let existingOption = null;
+                for (let option of tagsSelect.options) {
+                    if (option.text.toLowerCase() === tagName.toLowerCase()) {
+                        existingOption = option;
+                        break;
+                    }
+                }
+
+                if (existingOption) {
+                    // 选中已存在的标签
+                    existingOption.selected = true;
+                } else {
+                    // 创建新标签选项（使用负数ID表示新标签）
+                    const newOption = document.createElement('option');
+                    newOption.value = 'new_' + Date.now();
+                    newOption.text = tagName;
+                    newOption.selected = true;
+                    newOption.setAttribute('data-new-tag', 'true');
+                    tagsSelect.appendChild(newOption);
+                }
+
+                tagInput.value = '';
+                updateSelectedTags();
+            }
+        });
+
+        // 初始化显示
+        updateSelectedTags();
+
+        // 表单提交时处理新标签
+        const form = tagsSelect.closest('form');
+        form.addEventListener('submit', function(e) {
+            // 收集所有新标签名称
+            const newTags = [];
+            Array.from(tagsSelect.options).forEach(option => {
+                if (option.selected && option.hasAttribute('data-new-tag')) {
+                    newTags.push(option.text);
+                }
+            });
+
+            // 如果有新标签，添加到隐藏字段
+            if (newTags.length > 0) {
+                const hiddenInput = document.createElement('input');
+                hiddenInput.type = 'hidden';
+                hiddenInput.name = 'new_tags';
+                hiddenInput.value = newTags.join(',');
+                form.appendChild(hiddenInput);
+            }
+        });
+
+        // 在标签字段后添加"AI生成标签"按钮
         const generateBtn = document.createElement('button');
         generateBtn.type = 'button';
         generateBtn.className = 'btn btn-success generate-tags-btn';
@@ -141,8 +412,8 @@ document.addEventListener('DOMContentLoaded', function() {
         const tagsStatusDiv = document.createElement('div');
         tagsStatusDiv.className = 'tags-status';
 
-        tagsField.parentNode.appendChild(generateBtn);
-        tagsField.parentNode.appendChild(tagsStatusDiv);
+        tagInputWrapper.appendChild(generateBtn);
+        tagInputWrapper.appendChild(tagsStatusDiv);
 
         generateBtn.addEventListener('click', function() {
             const nameField = document.querySelector('input[name="name"]');
@@ -175,9 +446,31 @@ document.addEventListener('DOMContentLoaded', function() {
             .then(response => response.json())
             .then(data => {
                 if (data.success && data.tags && data.tags.length > 0) {
-                    // 显示生成的标签
-                    const tagsText = data.tags.join(', ');
-                    showTagsStatus('✓ AI生成的标签建议: ' + tagsText + '\n（请在标签字段中手动选择或创建这些标签）', 'success');
+                    // 自动添加生成的标签
+                    data.tags.forEach(tagName => {
+                        // 检查是否已存在
+                        let exists = false;
+                        for (let option of tagsSelect.options) {
+                            if (option.text.toLowerCase() === tagName.toLowerCase()) {
+                                option.selected = true;
+                                exists = true;
+                                break;
+                            }
+                        }
+
+                        // 如果不存在，创建新标签
+                        if (!exists) {
+                            const newOption = document.createElement('option');
+                            newOption.value = 'new_' + Date.now() + '_' + Math.random();
+                            newOption.text = tagName;
+                            newOption.selected = true;
+                            newOption.setAttribute('data-new-tag', 'true');
+                            tagsSelect.appendChild(newOption);
+                        }
+                    });
+
+                    updateSelectedTags();
+                    showTagsStatus('✓ AI已自动添加推荐标签：' + data.tags.join(', '), 'success');
                 } else {
                     showTagsStatus('✗ ' + (data.message || '标签生成失败'), 'error');
                 }
@@ -198,6 +491,152 @@ document.addEventListener('DOMContentLoaded', function() {
             tagsStatusDiv.style.display = 'block';
         }
     }
+
+    // 在Description字段后添加"AI生成详细介绍"按钮
+    const descriptionField = document.querySelector('textarea[name="description"]');
+    if (descriptionField) {
+        // 创建生成按钮
+        const generateDescBtn = document.createElement('button');
+        generateDescBtn.type = 'button';
+        generateDescBtn.className = 'btn btn-success generate-features-btn';
+        generateDescBtn.innerHTML = '<span class="normal-icon">✨</span><span class="loading-icon">↻</span> AI生成详细介绍';
+
+        const descStatusDiv = document.createElement('div');
+        descStatusDiv.className = 'tags-status';
+
+        descriptionField.parentNode.appendChild(generateDescBtn);
+        descriptionField.parentNode.appendChild(descStatusDiv);
+
+        generateDescBtn.addEventListener('click', function() {
+            const nameField = document.querySelector('input[name="name"]');
+            const shortDescField = document.querySelector('input[name="short_desc"]');
+            const urlField = document.querySelector('input[name="url"]');
+
+            const name = nameField ? nameField.value.trim() : '';
+            const shortDesc = shortDescField ? shortDescField.value.trim() : '';
+            const url = urlField ? urlField.value.trim() : '';
+
+            if (!name) {
+                showDescStatus('请先填写网站名称', 'error');
+                return;
+            }
+
+            // 显示加载状态
+            generateDescBtn.disabled = true;
+            generateDescBtn.classList.add('loading');
+            descStatusDiv.style.display = 'none';
+
+            // 调用API生成详细介绍
+            fetch('/api/generate-description', {
+                method: 'POST',
+                headers: {
+                    'Content-Type': 'application/json',
+                },
+                body: JSON.stringify({
+                    name: name,
+                    short_desc: shortDesc,
+                    url: url
+                })
+            })
+            .then(response => response.json())
+            .then(data => {
+                if (data.success && data.description) {
+                    // 自动填充到description字段
+                    descriptionField.value = data.description;
+                    showDescStatus('✓ AI已生成详细介绍', 'success');
+                } else {
+                    showDescStatus('✗ ' + (data.message || '详细介绍生成失败'), 'error');
+                }
+            })
+            .catch(error => {
+                console.error('Error:', error);
+                showDescStatus('✗ 网络请求失败，请重试', 'error');
+            })
+            .finally(() => {
+                generateDescBtn.disabled = false;
+                generateDescBtn.classList.remove('loading');
+            });
+        });
+
+        function showDescStatus(message, type) {
+            descStatusDiv.textContent = message;
+            descStatusDiv.className = 'tags-status ' + type;
+            descStatusDiv.style.display = 'block';
+        }
+    }
+
+    // 在Features字段后添加"AI生成功能"按钮
+    const featuresField = document.querySelector('textarea[name="features"]');
+    if (featuresField) {
+        // 创建生成按钮
+        const generateFeaturesBtn = document.createElement('button');
+        generateFeaturesBtn.type = 'button';
+        generateFeaturesBtn.className = 'btn btn-success generate-features-btn';
+        generateFeaturesBtn.innerHTML = '<span class="normal-icon">✨</span><span class="loading-icon">↻</span> AI生成主要功能';
+
+        const featuresStatusDiv = document.createElement('div');
+        featuresStatusDiv.className = 'tags-status';
+
+        featuresField.parentNode.appendChild(generateFeaturesBtn);
+        featuresField.parentNode.appendChild(featuresStatusDiv);
+
+        generateFeaturesBtn.addEventListener('click', function() {
+            const nameField = document.querySelector('input[name="name"]');
+            const descriptionField = document.querySelector('textarea[name="description"]');
+            const urlField = document.querySelector('input[name="url"]');
+
+            const name = nameField ? nameField.value.trim() : '';
+            const description = descriptionField ? descriptionField.value.trim() : '';
+            const url = urlField ? urlField.value.trim() : '';
+
+            if (!name || !description) {
+                showFeaturesStatus('请先填写网站名称和描述', 'error');
+                return;
+            }
+
+            // 显示加载状态
+            generateFeaturesBtn.disabled = true;
+            generateFeaturesBtn.classList.add('loading');
+            featuresStatusDiv.style.display = 'none';
+
+            // 调用API生成功能
+            fetch('/api/generate-features', {
+                method: 'POST',
+                headers: {
+                    'Content-Type': 'application/json',
+                },
+                body: JSON.stringify({
+                    name: name,
+                    description: description,
+                    url: url
+                })
+            })
+            .then(response => response.json())
+            .then(data => {
+                if (data.success && data.features) {
+                    // 自动填充到features字段
+                    featuresField.value = data.features;
+                    showFeaturesStatus('✓ AI已生成主要功能列表', 'success');
+                } else {
+                    showFeaturesStatus('✗ ' + (data.message || '功能生成失败'), 'error');
+                }
+            })
+            .catch(error => {
+                console.error('Error:', error);
+                showFeaturesStatus('✗ 网络请求失败，请重试', 'error');
+            })
+            .finally(() => {
+                generateFeaturesBtn.disabled = false;
+                generateFeaturesBtn.classList.remove('loading');
+            });
+        });
+
+        function showFeaturesStatus(message, type) {
+            featuresStatusDiv.textContent = message;
+            featuresStatusDiv.className = 'tags-status ' + type;
+            featuresStatusDiv.style.display = 'block';
+        }
+    }
 });
 </script>
 {% endblock %}
diff --git a/templates/admin/site/edit.html b/templates/admin/site/edit.html
index aef6d86..6594b5f 100644
--- a/templates/admin/site/edit.html
+++ b/templates/admin/site/edit.html
@@ -11,6 +11,28 @@
         margin-top: 10px;
         margin-bottom: 15px;
     }
+    .generate-features-btn {
+        margin-top: 10px;
+        margin-bottom: 15px;
+    }
+    .upload-logo-btn {
+        margin-top: 10px;
+        margin-bottom: 15px;
+    }
+    .logo-preview {
+        margin-top: 10px;
+        max-width: 200px;
+        max-height: 200px;
+        display: none;
+        border: 1px solid #ddd;
+        border-radius: 8px;
+        padding: 10px;
+    }
+    .logo-preview img {
+        max-width: 100%;
+        max-height: 150px;
+        object-fit: contain;
+    }
     .fetch-status {
         margin-top: 10px;
         padding: 10px;
@@ -47,6 +69,26 @@
         from { transform: rotate(0deg); }
         to { transform: rotate(360deg); }
     }
+    /* 标签输入框样式 */
+    .tag-input-wrapper {
+        margin-top: 10px;
+    }
+    .tag-input-field {
+        width: 100%;
+        padding: 8px 12px;
+        border: 1px solid #DCDFE6;
+        border-radius: 4px;
+        font-size: 14px;
+    }
+    .tag-input-field:focus {
+        outline: none;
+        border-color: #0052D9;
+    }
+    .tag-input-help {
+        margin-top: 5px;
+        font-size: 12px;
+        color: #606266;
+    }
 </style>
 
 <script>
@@ -130,72 +172,490 @@ document.addEventListener('DOMContentLoaded', function() {
         }
     }
 
-    // 在标签字段后添加"AI生成标签"按钮
-    const tagsField = document.querySelector('select[name="tags"]');
-    if (tagsField) {
-        const generateBtn = document.createElement('button');
-        generateBtn.type = 'button';
-        generateBtn.className = 'btn btn-success generate-tags-btn';
-        generateBtn.innerHTML = '<span class="normal-icon">✨</span><span class="loading-icon">↻</span> AI生成标签';
+    // 在Logo字段后添加"上传Logo"功能
+    const logoField = document.querySelector('input[name="logo"]');
+    if (logoField) {
+        // 创建文件输入框
+        const fileInput = document.createElement('input');
+        fileInput.type = 'file';
+        fileInput.accept = 'image/*';
+        fileInput.style.display = 'none';
+
+        // 创建上传按钮
+        const uploadBtn = document.createElement('button');
+        uploadBtn.type = 'button';
+        uploadBtn.className = 'btn btn-warning upload-logo-btn';
+        uploadBtn.innerHTML = '📁 上传Logo图片';
+
+        // 创建预览容器
+        const previewDiv = document.createElement('div');
+        previewDiv.className = 'logo-preview';
+        previewDiv.innerHTML = '<img src="" alt="Logo预览"><p style="margin-top:5px; font-size:12px; color:#666;">Logo预览</p>';
+
+        logoField.parentNode.appendChild(fileInput);
+        logoField.parentNode.appendChild(uploadBtn);
+        logoField.parentNode.appendChild(previewDiv);
+
+        // 点击按钮触发文件选择
+        uploadBtn.addEventListener('click', function() {
+            fileInput.click();
+        });
+
+        // 文件选择后自动上传
+        fileInput.addEventListener('change', function() {
+            const file = fileInput.files[0];
+            if (!file) return;
+
+            // 验证文件类型
+            if (!file.type.startsWith('image/')) {
+                alert('请选择图片文件！');
+                return;
+            }
+
+            // 验证文件大小（限制5MB）
+            if (file.size > 5 * 1024 * 1024) {
+                alert('图片文件不能超过5MB！');
+                return;
+            }
+
+            // 上传文件
+            const formData = new FormData();
+            formData.append('logo', file);
+
+            uploadBtn.disabled = true;
+            uploadBtn.textContent = '上传中...';
+
+            fetch('/api/upload-logo', {
+                method: 'POST',
+                body: formData
+            })
+            .then(response => response.json())
+            .then(data => {
+                if (data.success) {
+                    // 设置Logo字段值
+                    logoField.value = data.path;
+
+                    // 显示预览
+                    const img = previewDiv.querySelector('img');
+                    img.src = data.path;
+                    previewDiv.style.display = 'block';
+
+                    alert('✓ Logo上传成功！');
+                } else {
+                    alert('✗ ' + (data.message || '上传失败'));
+                }
+            })
+            .catch(error => {
+                console.error('Error:', error);
+                alert('✗ 上传失败，请重试');
+            })
+            .finally(() => {
+                uploadBtn.disabled = false;
+                uploadBtn.innerHTML = '📁 上传Logo图片';
+                fileInput.value = '';
+            });
+        });
+
+        // 如果Logo字段有值，显示预览
+        if (logoField.value) {
+            const img = previewDiv.querySelector('img');
+            img.src = logoField.value;
+            previewDiv.style.display = 'block';
+        }
+
+        // 监听Logo字段变化，更新预览
+        logoField.addEventListener('input', function() {
+            if (logoField.value) {
+                const img = previewDiv.querySelector('img');
+                img.src = logoField.value;
+                previewDiv.style.display = 'block';
+            } else {
+                previewDiv.style.display = 'none';
+            }
+        });
+    }
+
+    // 处理标签字段 - 添加手动输入功能
+    const tagsSelect = document.querySelector('select[name="tags"]');
+    if (tagsSelect) {
+        // 先等待一下，确保 Flask-Admin 已经初始化好 select
+        setTimeout(function() {
+            // 保存原始选中的标签（从数据库加载的）
+            const originalSelectedOptions = Array.from(tagsSelect.selectedOptions);
+
+            // 隐藏原始的select字段
+            tagsSelect.style.display = 'none';
+
+            // 创建文本输入框
+            const tagInputWrapper = document.createElement('div');
+            tagInputWrapper.className = 'tag-input-wrapper';
+
+            const tagInput = document.createElement('input');
+            tagInput.type = 'text';
+            tagInput.className = 'tag-input-field';
+            tagInput.placeholder = '输入标签名称，按回车添加（如：AI工具、图像处理、免费）';
+
+            const tagHelpText = document.createElement('div');
+            tagHelpText.className = 'tag-input-help';
+            tagHelpText.textContent = '💡 提示：输入标签名称后按回车键添加，可以添加多个标签。已选标签会自动添加到下方列表。';
+
+            const selectedTagsDiv = document.createElement('div');
+            selectedTagsDiv.className = 'selected-tags';
+            selectedTagsDiv.style.marginTop = '10px';
+
+            tagInputWrapper.appendChild(tagInput);
+            tagInputWrapper.appendChild(tagHelpText);
+            tagInputWrapper.appendChild(selectedTagsDiv);
+            tagsSelect.parentNode.insertBefore(tagInputWrapper, tagsSelect.nextSibling);
+
+            // 显示已选标签
+            function updateSelectedTags() {
+                selectedTagsDiv.innerHTML = '';
+                const selectedOptions = Array.from(tagsSelect.selectedOptions);
+
+                // 如果没有选中的标签，显示提示
+                if (selectedOptions.length === 0) {
+                    selectedTagsDiv.innerHTML = '<span style="color:#999; font-size:12px;">暂无已选标签</span>';
+                    return;
+                }
+
+                selectedOptions.forEach(option => {
+                    const tag = document.createElement('span');
+                    tag.style.cssText = 'display:inline-block; background:#0052D9; color:white; padding:4px 10px; margin:4px; border-radius:4px; font-size:12px;';
+
+                    // 获取标签文本 - 兼容多种方式
+                    let tagText = option.textContent || option.innerText || option.text || option.innerHTML || option.label || `标签${option.value}`;
+
+                    // 处理 <Tag XXX> 格式，提取出实际标签名称
+                    const match = tagText.match(/<Tag\s+(.+?)>/);
+                    if (match) {
+                        tagText = match[1];  // 提取标签名称
+                    }
+
+                    tag.innerHTML = tagText + ' <span style="cursor:pointer; margin-left:5px; font-weight:bold;" data-tag-id="' + option.value + '">×</span>';
+                    selectedTagsDiv.appendChild(tag);
+
+                    // 为删除按钮添加点击事件
+                    const deleteBtn = tag.querySelector('span[data-tag-id]');
+                    if (deleteBtn) {
+                        deleteBtn.addEventListener('click', function(e) {
+                            e.stopPropagation();
+                            option.selected = false;
+                            updateSelectedTags();
+                        });
+                    }
+                });
+            }
+
+            // 添加标签
+            tagInput.addEventListener('keypress', function(e) {
+                if (e.key === 'Enter') {
+                    e.preventDefault();
+                    const tagName = tagInput.value.trim();
+
+                    if (!tagName) {
+                        return;
+                    }
+
+                    // 检查标签是否已存在
+                    let existingOption = null;
+                    for (let option of tagsSelect.options) {
+                        if (option.text.toLowerCase() === tagName.toLowerCase()) {
+                            existingOption = option;
+                            break;
+                        }
+                    }
+
+                    if (existingOption) {
+                        // 选中已存在的标签
+                        existingOption.selected = true;
+                    } else {
+                        // 创建新标签选项（使用负数ID表示新标签）
+                        const newOption = document.createElement('option');
+                        newOption.value = 'new_' + Date.now();
+                        newOption.text = tagName;
+                        newOption.selected = true;
+                        newOption.setAttribute('data-new-tag', 'true');
+                        tagsSelect.appendChild(newOption);
+                    }
+
+                    tagInput.value = '';
+                    updateSelectedTags();
+                }
+            });
+
+            // 初始化显示 - 使用延迟确保数据已加载
+            updateSelectedTags();
+
+            // 再次确保原始选中的标签保持选中状态
+            originalSelectedOptions.forEach(opt => {
+                // 在所有选项中找到对应的选项并设置为选中
+                for (let option of tagsSelect.options) {
+                    if (option.value === opt.value) {
+                        option.selected = true;
+                    }
+                }
+            });
+
+            // 再次更新显示
+            setTimeout(function() {
+                updateSelectedTags();
+            }, 100);
+
+            // 表单提交时处理新标签
+            const form = tagsSelect.closest('form');
+            form.addEventListener('submit', function(e) {
+                // 收集所有新标签名称
+                const newTags = [];
+                Array.from(tagsSelect.options).forEach(option => {
+                    if (option.selected && option.hasAttribute('data-new-tag')) {
+                        newTags.push(option.text);
+                    }
+                });
+
+                // 如果有新标签，添加到隐藏字段
+                if (newTags.length > 0) {
+                    const hiddenInput = document.createElement('input');
+                    hiddenInput.type = 'hidden';
+                    hiddenInput.name = 'new_tags';
+                    hiddenInput.value = newTags.join(',');
+                    form.appendChild(hiddenInput);
+                }
+            });
+
+            // 在标签字段后添加"AI生成标签"按钮
+            const generateBtn = document.createElement('button');
+            generateBtn.type = 'button';
+            generateBtn.className = 'btn btn-success generate-tags-btn';
+            generateBtn.innerHTML = '<span class="normal-icon">✨</span><span class="loading-icon">↻</span> AI生成标签';
+
+            const tagsStatusDiv = document.createElement('div');
+            tagsStatusDiv.className = 'tags-status';
+
+            tagInputWrapper.appendChild(generateBtn);
+            tagInputWrapper.appendChild(tagsStatusDiv);
+
+            generateBtn.addEventListener('click', function() {
+                const nameField = document.querySelector('input[name="name"]');
+                const descriptionField = document.querySelector('textarea[name="description"]');
+
+                const name = nameField ? nameField.value.trim() : '';
+                const description = descriptionField ? descriptionField.value.trim() : '';
+
+                if (!name || !description) {
+                    showTagsStatus('请先填写网站名称和描述', 'error');
+                    return;
+                }
+
+                // 显示加载状态
+                generateBtn.disabled = true;
+                generateBtn.classList.add('loading');
+                tagsStatusDiv.style.display = 'none';
+
+                // 调用API生成标签
+                fetch('/api/generate-tags', {
+                    method: 'POST',
+                    headers: {
+                        'Content-Type': 'application/json',
+                    },
+                    body: JSON.stringify({
+                        name: name,
+                        description: description
+                    })
+                })
+                .then(response => response.json())
+                .then(data => {
+                    if (data.success && data.tags && data.tags.length > 0) {
+                        // 自动添加生成的标签
+                        data.tags.forEach(tagName => {
+                            // 检查是否已存在
+                            let exists = false;
+                            for (let option of tagsSelect.options) {
+                                if (option.text.toLowerCase() === tagName.toLowerCase()) {
+                                    option.selected = true;
+                                    exists = true;
+                                    break;
+                                }
+                            }
+
+                            // 如果不存在，创建新标签
+                            if (!exists) {
+                                const newOption = document.createElement('option');
+                                newOption.value = 'new_' + Date.now() + '_' + Math.random();
+                                newOption.text = tagName;
+                                newOption.selected = true;
+                                newOption.setAttribute('data-new-tag', 'true');
+                                tagsSelect.appendChild(newOption);
+                            }
+                        });
+
+                        updateSelectedTags();
+                        showTagsStatus('✓ AI已自动添加推荐标签：' + data.tags.join(', '), 'success');
+                    } else {
+                        showTagsStatus('✗ ' + (data.message || '标签生成失败'), 'error');
+                    }
+                })
+                .catch(error => {
+                    console.error('Error:', error);
+                    showTagsStatus('✗ 网络请求失败，请重试', 'error');
+                })
+                .finally(() => {
+                    generateBtn.disabled = false;
+                    generateBtn.classList.remove('loading');
+                });
+            });
+
+            function showTagsStatus(message, type) {
+                tagsStatusDiv.textContent = message;
+                tagsStatusDiv.className = 'tags-status ' + type;
+                tagsStatusDiv.style.display = 'block';
+            }
+        }, 50); // setTimeout 结束
+    }
+
+    // 在Description字段后添加"AI生成详细介绍"按钮
+    const descriptionField = document.querySelector('textarea[name="description"]');
+    if (descriptionField) {
+        // 创建生成按钮
+        const generateDescBtn = document.createElement('button');
+        generateDescBtn.type = 'button';
+        generateDescBtn.className = 'btn btn-success generate-features-btn';
+        generateDescBtn.innerHTML = '<span class="normal-icon">✨</span><span class="loading-icon">↻</span> AI生成详细介绍';
+
+        const descStatusDiv = document.createElement('div');
+        descStatusDiv.className = 'tags-status';
+
+        descriptionField.parentNode.appendChild(generateDescBtn);
+        descriptionField.parentNode.appendChild(descStatusDiv);
+
+        generateDescBtn.addEventListener('click', function() {
+            const nameField = document.querySelector('input[name="name"]');
+            const shortDescField = document.querySelector('input[name="short_desc"]');
+            const urlField = document.querySelector('input[name="url"]');
+
+            const name = nameField ? nameField.value.trim() : '';
+            const shortDesc = shortDescField ? shortDescField.value.trim() : '';
+            const url = urlField ? urlField.value.trim() : '';
+
+            if (!name) {
+                showDescStatus('请先填写网站名称', 'error');
+                return;
+            }
+
+            // 显示加载状态
+            generateDescBtn.disabled = true;
+            generateDescBtn.classList.add('loading');
+            descStatusDiv.style.display = 'none';
+
+            // 调用API生成详细介绍
+            fetch('/api/generate-description', {
+                method: 'POST',
+                headers: {
+                    'Content-Type': 'application/json',
+                },
+                body: JSON.stringify({
+                    name: name,
+                    short_desc: shortDesc,
+                    url: url
+                })
+            })
+            .then(response => response.json())
+            .then(data => {
+                if (data.success && data.description) {
+                    // 自动填充到description字段
+                    descriptionField.value = data.description;
+                    showDescStatus('✓ AI已生成详细介绍', 'success');
+                } else {
+                    showDescStatus('✗ ' + (data.message || '详细介绍生成失败'), 'error');
+                }
+            })
+            .catch(error => {
+                console.error('Error:', error);
+                showDescStatus('✗ 网络请求失败，请重试', 'error');
+            })
+            .finally(() => {
+                generateDescBtn.disabled = false;
+                generateDescBtn.classList.remove('loading');
+            });
+        });
+
+        function showDescStatus(message, type) {
+            descStatusDiv.textContent = message;
+            descStatusDiv.className = 'tags-status ' + type;
+            descStatusDiv.style.display = 'block';
+        }
+    }
+
+    // 在Features字段后添加"AI生成功能"按钮
+    const featuresField = document.querySelector('textarea[name="features"]');
+    if (featuresField) {
+        // 创建生成按钮
+        const generateFeaturesBtn = document.createElement('button');
+        generateFeaturesBtn.type = 'button';
+        generateFeaturesBtn.className = 'btn btn-success generate-features-btn';
+        generateFeaturesBtn.innerHTML = '<span class="normal-icon">✨</span><span class="loading-icon">↻</span> AI生成主要功能';
 
-        const tagsStatusDiv = document.createElement('div');
-        tagsStatusDiv.className = 'tags-status';
+        const featuresStatusDiv = document.createElement('div');
+        featuresStatusDiv.className = 'tags-status';
 
-        tagsField.parentNode.appendChild(generateBtn);
-        tagsField.parentNode.appendChild(tagsStatusDiv);
+        featuresField.parentNode.appendChild(generateFeaturesBtn);
+        featuresField.parentNode.appendChild(featuresStatusDiv);
 
-        generateBtn.addEventListener('click', function() {
+        generateFeaturesBtn.addEventListener('click', function() {
             const nameField = document.querySelector('input[name="name"]');
             const descriptionField = document.querySelector('textarea[name="description"]');
+            const urlField = document.querySelector('input[name="url"]');
 
             const name = nameField ? nameField.value.trim() : '';
             const description = descriptionField ? descriptionField.value.trim() : '';
+            const url = urlField ? urlField.value.trim() : '';
 
             if (!name || !description) {
-                showTagsStatus('请先填写网站名称和描述', 'error');
+                showFeaturesStatus('请先填写网站名称和描述', 'error');
                 return;
             }
 
             // 显示加载状态
-            generateBtn.disabled = true;
-            generateBtn.classList.add('loading');
-            tagsStatusDiv.style.display = 'none';
+            generateFeaturesBtn.disabled = true;
+            generateFeaturesBtn.classList.add('loading');
+            featuresStatusDiv.style.display = 'none';
 
-            // 调用API生成标签
-            fetch('/api/generate-tags', {
+            // 调用API生成功能
+            fetch('/api/generate-features', {
                 method: 'POST',
                 headers: {
                     'Content-Type': 'application/json',
                 },
                 body: JSON.stringify({
                     name: name,
-                    description: description
+                    description: description,
+                    url: url
                 })
             })
             .then(response => response.json())
             .then(data => {
-                if (data.success && data.tags && data.tags.length > 0) {
-                    // 显示生成的标签
-                    const tagsText = data.tags.join(', ');
-                    showTagsStatus('✓ AI生成的标签建议: ' + tagsText + '\n（请在标签字段中手动选择或创建这些标签）', 'success');
+                if (data.success && data.features) {
+                    // 自动填充到features字段
+                    featuresField.value = data.features;
+                    showFeaturesStatus('✓ AI已生成主要功能列表', 'success');
                 } else {
-                    showTagsStatus('✗ ' + (data.message || '标签生成失败'), 'error');
+                    showFeaturesStatus('✗ ' + (data.message || '功能生成失败'), 'error');
                 }
             })
             .catch(error => {
                 console.error('Error:', error);
-                showTagsStatus('✗ 网络请求失败，请重试', 'error');
+                showFeaturesStatus('✗ 网络请求失败，请重试', 'error');
             })
             .finally(() => {
-                generateBtn.disabled = false;
-                generateBtn.classList.remove('loading');
+                generateFeaturesBtn.disabled = false;
+                generateFeaturesBtn.classList.remove('loading');
             });
         });
 
-        function showTagsStatus(message, type) {
-            tagsStatusDiv.textContent = message;
-            tagsStatusDiv.className = 'tags-status ' + type;
-            tagsStatusDiv.style.display = 'block';
+        function showFeaturesStatus(message, type) {
+            featuresStatusDiv.textContent = message;
+            featuresStatusDiv.className = 'tags-status ' + type;
+            featuresStatusDiv.style.display = 'block';
         }
     }
 });
diff --git a/templates/base_new.html b/templates/base_new.html
index 627d8e6..1252bec 100644
--- a/templates/base_new.html
+++ b/templates/base_new.html
@@ -5,14 +5,6 @@
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>{% block title %}ZJPB - 焦提示词 | AI工具导航{% endblock %}</title>
 
-    <!-- Google Fonts -->
-    <link rel="preconnect" href="https://fonts.googleapis.com">
-    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
-
-    <!-- Material Symbols -->
-    <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
-
     <style>
         * {
             margin: 0;
@@ -38,7 +30,7 @@
         }
 
         body {
-            font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
+            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
             background: var(--bg-page);
             color: var(--text-primary);
             line-height: 1.6;
@@ -139,12 +131,12 @@
             background: var(--bg-white);
         }
 
-        .search-box .material-symbols-outlined {
+        .search-box .search-icon {
             position: absolute;
             left: 10px;
             top: 50%;
             transform: translateY(-50%);
-            font-size: 20px;
+            font-size: 16px;
             color: var(--text-muted);
         }
 
@@ -235,7 +227,7 @@
             <div class="nav-left">
                 <a href="/" class="nav-logo">
                     <div class="nav-logo-icon">
-                        <span class="material-symbols-outlined" style="font-size: 20px;">blur_on</span>
+                        <span style="font-size: 20px;">✦</span>
                     </div>
                     <span>ZJPB</span>
                 </a>
@@ -247,7 +239,7 @@
             </div>
             <div class="nav-right">
                 <form action="/" method="get" class="search-box">
-                    <span class="material-symbols-outlined">search</span>
+                    <span class="search-icon">🔍</span>
                     <input type="text" name="q" placeholder="搜索 AI 工具..." value="{{ search_query or '' }}">
                 </form>
                 <a href="/admin/login" class="btn btn-secondary">登录</a>
@@ -263,16 +255,30 @@
     <footer class="footer">
         <div class="footer-container">
             <div class="footer-text">
-                © 2023 ZJPB AI Directory. All rights reserved.
+                <div>© 2025 ZJPB - 焦提示词 | AI工具导航. All rights reserved.</div>
+                <div style="margin-top: 8px;">
+                    <a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener noreferrer" style="color: var(--text-secondary); text-decoration: none;">
+                        浙ICP备2025154782号-1
+                    </a>
+                </div>
             </div>
             <div class="footer-links">
-                <a href="#">Twitter</a>
-                <a href="#">Discord</a>
-                <a href="#">Privacy Policy</a>
+                <a href="#">关于我们</a>
+                <a href="#">隐私政策</a>
+                <a href="#">用户协议</a>
             </div>
         </div>
     </footer>
 
+    <!-- Microsoft Clarity 统计代码 -->
+    <script type="text/javascript">
+        (function(c,l,a,r,i,t,y){
+            c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
+            t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
+            y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
+        })(window, document, "clarity", "script", "uoa2j40sf0");
+    </script>
+
     {% block extra_js %}{% endblock %}
 </body>
 </html>
diff --git a/templates/detail_new.html b/templates/detail_new.html
index 1033f7c..c84192f 100644
--- a/templates/detail_new.html
+++ b/templates/detail_new.html
@@ -20,12 +20,6 @@
         color: var(--text-primary);
     }
 
-    .back-link .material-symbols-outlined {
-        font-size: 24px;
-        line-height: 1;
-        vertical-align: middle;
-        margin-top: -2px;
-    }
 
     /* 产品头部区域 */
     .product-header-wrapper {
@@ -84,9 +78,6 @@
         text-decoration: underline;
     }
 
-    .product-link .material-symbols-outlined {
-        font-size: 16px;
-    }
 
     .product-meta {
         display: flex;
@@ -103,9 +94,6 @@
         font-size: 14px;
     }
 
-    .meta-item .material-symbols-outlined {
-        font-size: 18px;
-    }
 
     .product-tags-list {
         display: flex;
@@ -195,9 +183,6 @@
         box-shadow: 0 4px 12px rgba(14, 165, 233, 0.3);
     }
 
-    .visit-btn .material-symbols-outlined {
-        font-size: 18px;
-    }
 
     .visit-hint {
         text-align: center;
@@ -242,10 +227,6 @@
         margin-bottom: 20px;
     }
 
-    .content-block h2 .material-symbols-outlined {
-        font-size: 24px;
-        color: var(--primary-blue);
-    }
 
     .content-block p {
         color: var(--text-secondary);
@@ -399,6 +380,126 @@
         font-weight: 500;
     }
 
+    /* Markdown内容样式 */
+    .markdown-content {
+        color: var(--text-secondary);
+        line-height: 1.8;
+    }
+
+    .markdown-content h1,
+    .markdown-content h2,
+    .markdown-content h3 {
+        color: var(--text-primary);
+        font-weight: 600;
+        margin-top: 24px;
+        margin-bottom: 16px;
+        line-height: 1.4;
+    }
+
+    .markdown-content h1 {
+        font-size: 24px;
+    }
+
+    .markdown-content h2 {
+        font-size: 20px;
+    }
+
+    .markdown-content h3 {
+        font-size: 18px;
+    }
+
+    .markdown-content p {
+        margin-bottom: 16px;
+        line-height: 1.8;
+    }
+
+    .markdown-content ul,
+    .markdown-content ol {
+        margin: 16px 0;
+        padding-left: 24px;
+    }
+
+    .markdown-content ul li {
+        list-style: none;
+        position: relative;
+        padding-left: 20px;
+        margin-bottom: 12px;
+        line-height: 1.8;
+    }
+
+    .markdown-content ul li:before {
+        content: "▸";
+        position: absolute;
+        left: 0;
+        color: var(--primary-blue);
+        font-weight: bold;
+    }
+
+    .markdown-content ol li {
+        margin-bottom: 12px;
+        line-height: 1.8;
+        padding-left: 8px;
+    }
+
+    .markdown-content code {
+        background: #f1f5f9;
+        color: #e11d48;
+        padding: 2px 6px;
+        border-radius: 4px;
+        font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
+        font-size: 0.9em;
+    }
+
+    .markdown-content pre {
+        background: #1e293b;
+        color: #e2e8f0;
+        padding: 16px;
+        border-radius: 8px;
+        overflow-x: auto;
+        margin: 16px 0;
+    }
+
+    .markdown-content pre code {
+        background: transparent;
+        color: inherit;
+        padding: 0;
+        border-radius: 0;
+    }
+
+    .markdown-content strong {
+        font-weight: 600;
+        color: var(--text-primary);
+    }
+
+    .markdown-content em {
+        font-style: italic;
+    }
+
+    .markdown-content a {
+        color: var(--primary-blue);
+        text-decoration: none;
+        border-bottom: 1px solid transparent;
+        transition: border-color 0.2s;
+    }
+
+    .markdown-content a:hover {
+        border-bottom-color: var(--primary-blue);
+    }
+
+    .markdown-content blockquote {
+        border-left: 4px solid var(--primary-blue);
+        padding-left: 16px;
+        margin: 16px 0;
+        color: var(--text-secondary);
+        font-style: italic;
+    }
+
+    .markdown-content hr {
+        border: none;
+        border-top: 1px solid var(--border-color);
+        margin: 24px 0;
+    }
+
     /* 响应式 */
     @media (max-width: 968px) {
         .product-header-wrapper {
@@ -432,7 +533,7 @@
 
     <!-- 返回链接 -->
     <a href="/" class="back-link">
-        <span class="material-symbols-outlined">arrow_back</span>
+        <span>←</span>
         返回首页
     </a>
 
@@ -456,16 +557,16 @@
                     <h1>{{ site.name }}</h1>
                     <a href="{{ site.url }}" target="_blank" class="product-link">
                         {{ site.url }}
-                        <span class="material-symbols-outlined">open_in_new</span>
+                        <span>↗</span>
                     </a>
 
                     <div class="product-meta">
                         <div class="meta-item">
-                            <span class="material-symbols-outlined">visibility</span>
+                            <span>👁</span>
                             <span>{{ site.view_count | default(0) }} 次浏览</span>
                         </div>
                         <div class="meta-item">
-                            <span class="material-symbols-outlined">calendar_today</span>
+                            <span>📅</span>
                             <span>添加于 {{ site.created_at.strftime('%Y年%m月%d日') }}</span>
                         </div>
                     </div>
@@ -488,7 +589,7 @@
             </div>
             <a href="{{ site.url }}" target="_blank" class="visit-btn">
                 访问网站
-                <span class="material-symbols-outlined">north_east</span>
+                <span>↗</span>
             </a>
             <p class="visit-hint">在新标签页打开 • {{ site.url.split('/')[2] if site.url else '' }}</p>
         </div>
@@ -501,20 +602,20 @@
             <!-- Product Overview -->
             <div class="content-block">
                 <h2>
-                    <span class="material-symbols-outlined">info</span>
+                    <span>ℹ️</span>
                     产品概述
                 </h2>
-                <p>{{ site.description }}</p>
+                <div class="markdown-content">{{ site.description | markdown | safe }}</div>
             </div>
 
             <!-- Detailed Description -->
             {% if site.features %}
             <div class="content-block">
                 <h2>
-                    <span class="material-symbols-outlined">description</span>
-                    详细描述
+                    <span>📋</span>
+                    主要功能
                 </h2>
-                <div>{{ site.features | safe }}</div>
+                <div class="markdown-content">{{ site.features | markdown | safe }}</div>
             </div>
             {% endif %}
 
@@ -522,7 +623,7 @@
             {% if news_list %}
             <div class="content-block">
                 <h2>
-                    <span class="material-symbols-outlined">newspaper</span>
+                    <span>📰</span>
                     相关新闻
                 </h2>
                 {% for news in news_list %}
@@ -540,7 +641,7 @@
             {% if recommended_sites %}
             <div class="content-block">
                 <h2>
-                    <span class="material-symbols-outlined">auto_awesome</span>
+                    <span>✨</span>
                     相似推荐
                 </h2>
                 <div class="recommendations-grid">
@@ -560,7 +661,7 @@
                                 {% endfor %}
                             </div>
                         </div>
-                        <span class="material-symbols-outlined arrow-icon">north_east</span>
+                        <span class="arrow-icon">↗</span>
                     </a>
                     {% endfor %}
                 </div>
-- 
2.50.1.windows.1

