diff --git a/config/__pycache__/local.cpython-312.pyc b/config/__pycache__/local.cpython-312.pyc index 85117a6..ec7e862 100644 Binary files a/config/__pycache__/local.cpython-312.pyc and b/config/__pycache__/local.cpython-312.pyc differ diff --git a/create_admin.py b/create_admin.py new file mode 100644 index 0000000..bd42bd5 --- /dev/null +++ b/create_admin.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +创建管理员账户脚本 +""" +from src.flask_prompt_master import create_app, db +from src.flask_prompt_master.admin.models.admin_user import AdminUser + +def create_admin_user(): + """创建管理员用户""" + app = create_app() + + with app.app_context(): + try: + # 检查是否已存在管理员 + admin = AdminUser.query.filter_by(username='admin').first() + if admin: + print("✅ 管理员账户已存在") + return + + # 创建管理员账户 + admin = AdminUser( + username='admin', + password='admin123', + email='admin@example.com', + role='super_admin' + ) + + db.session.add(admin) + db.session.commit() + + print("✅ 管理员账户创建成功") + print("用户名: admin") + print("密码: admin123") + print("请及时修改默认密码!") + + except Exception as e: + print(f"❌ 创建管理员账户失败: {str(e)}") + db.session.rollback() + +if __name__ == '__main__': + create_admin_user() diff --git a/migrations/__pycache__/env.cpython-312.pyc b/migrations/__pycache__/env.cpython-312.pyc index 0447373..75d85dc 100644 Binary files a/migrations/__pycache__/env.cpython-312.pyc and b/migrations/__pycache__/env.cpython-312.pyc differ diff --git a/migrations/versions/89df165acd11_add_admin_user_table.py b/migrations/versions/89df165acd11_add_admin_user_table.py new file mode 100644 index 0000000..81bb425 --- /dev/null +++ b/migrations/versions/89df165acd11_add_admin_user_table.py @@ -0,0 +1,41 @@ +"""Add admin user table + +Revision ID: 89df165acd11 +Revises: e1ec7bb6c8ec +Create Date: 2025-08-29 21:47:36.122009 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '89df165acd11' +down_revision = 'e1ec7bb6c8ec' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('admin_user', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('username', sa.String(length=50), nullable=False, comment='用户名'), + sa.Column('password_hash', sa.String(length=128), nullable=False, comment='密码哈希'), + sa.Column('email', sa.String(length=100), nullable=False, comment='邮箱'), + sa.Column('role', sa.String(length=20), nullable=False, comment='角色'), + sa.Column('is_active', sa.Boolean(), nullable=True, comment='是否激活'), + sa.Column('last_login', sa.DateTime(), nullable=True, comment='最后登录时间'), + sa.Column('created_at', sa.DateTime(), nullable=True, comment='创建时间'), + sa.Column('updated_at', sa.DateTime(), nullable=True, comment='更新时间'), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('email'), + sa.UniqueConstraint('username') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('admin_user') + # ### end Alembic commands ### diff --git a/migrations/versions/__pycache__/89df165acd11_add_admin_user_table.cpython-312.pyc b/migrations/versions/__pycache__/89df165acd11_add_admin_user_table.cpython-312.pyc new file mode 100644 index 0000000..bb469e1 Binary files /dev/null and b/migrations/versions/__pycache__/89df165acd11_add_admin_user_table.cpython-312.pyc differ diff --git a/migrations/versions/__pycache__/e1ec7bb6c8ec_add_favorites_table.cpython-312.pyc b/migrations/versions/__pycache__/e1ec7bb6c8ec_add_favorites_table.cpython-312.pyc index f57d46d..bfcc5bd 100644 Binary files a/migrations/versions/__pycache__/e1ec7bb6c8ec_add_favorites_table.cpython-312.pyc and b/migrations/versions/__pycache__/e1ec7bb6c8ec_add_favorites_table.cpython-312.pyc differ diff --git a/src/flask_prompt_master/__init__.py b/src/flask_prompt_master/__init__.py index 2bdd757..ca2d115 100644 --- a/src/flask_prompt_master/__init__.py +++ b/src/flask_prompt_master/__init__.py @@ -51,6 +51,10 @@ def create_app(config_class=None): # 注册认证蓝图 from src.flask_prompt_master.routes.auth import auth_bp app.register_blueprint(auth_bp) + + # 初始化后台管理 + from src.flask_prompt_master.admin import init_admin + init_admin(app) # 记录应用启动信息 app.logger.info(f"应用启动 - 环境: {os.environ.get('FLASK_ENV', 'development')}") diff --git a/src/flask_prompt_master/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/__pycache__/__init__.cpython-312.pyc index bf8f8f0..459a97c 100644 Binary files a/src/flask_prompt_master/__pycache__/__init__.cpython-312.pyc and b/src/flask_prompt_master/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/__init__.py b/src/flask_prompt_master/admin/__init__.py new file mode 100644 index 0000000..45a44e8 --- /dev/null +++ b/src/flask_prompt_master/admin/__init__.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- +""" +后台管理模块 +""" +from flask_admin import Admin, BaseView, expose +from flask_login import LoginManager, login_user, logout_user, login_required, current_user +from flask import redirect, url_for, request, flash, render_template +from src.flask_prompt_master import db +from src.flask_prompt_master.models.models import User, Prompt, PromptTemplate +from .models.admin_user import AdminUser +from .forms.admin_forms import AdminLoginForm +from .views.user_admin import UserAdminView +from .views.prompt_admin import PromptAdminView +from .views.template_admin import TemplateAdminView +from .views.system_admin import SystemAdminView +from datetime import datetime + +# 创建登录管理器 +login_manager = LoginManager() + +@login_manager.user_loader +def load_user(user_id): + """加载用户""" + return AdminUser.query.get(int(user_id)) + +def init_admin(app): + """初始化后台管理""" + # 初始化登录管理器 + login_manager.init_app(app) + login_manager.login_view = 'admin.login' + login_manager.login_message = '请先登录' + + # 创建Admin实例 + admin = Admin(app, name='提示词大师后台管理', template_mode='bootstrap4') + + # 注册视图 + admin.add_view(UserAdminView(User, db.session, name='用户管理', endpoint='admin_user')) + admin.add_view(PromptAdminView(Prompt, db.session, name='提示词管理', endpoint='admin_prompt')) + admin.add_view(TemplateAdminView(PromptTemplate, db.session, name='模板管理', endpoint='admin_template')) + admin.add_view(SystemAdminView(name='系统管理', endpoint='admin_system')) + + # 注册登录路由 + app.add_url_rule('/admin/login', 'admin.login', admin_login, methods=['GET', 'POST']) + app.add_url_rule('/admin/logout', 'admin.logout', admin_logout) + + return admin + +def admin_login(): + """管理员登录""" + if current_user.is_authenticated: + return redirect(url_for('admin.index')) + + form = AdminLoginForm() + if form.validate_on_submit(): + user = AdminUser.query.filter_by(username=form.username.data).first() + if user and user.check_password(form.password.data) and user.is_active: + login_user(user, remember=form.remember_me.data) + user.last_login = datetime.utcnow() + db.session.commit() + next_page = request.args.get('next') + return redirect(next_page or url_for('admin.index')) + else: + flash('用户名或密码错误', 'error') + + return render_template('admin/login.html', form=form) + +@login_required +def admin_logout(): + """管理员登出""" + logout_user() + flash('已成功登出', 'success') + return redirect(url_for('admin.login')) + +class AdminIndexView(BaseView): + """管理后台首页""" + + def is_accessible(self): + """检查访问权限""" + return current_user.is_authenticated + + @expose('/') + @login_required + def index(self): + """管理后台首页""" + # 获取统计数据 + from src.flask_prompt_master.models.models import User, Prompt, PromptTemplate + from sqlalchemy import func + from datetime import datetime, timedelta + + try: + # 用户统计 + total_users = User.query.count() + active_users = User.query.filter_by(status=1).count() + + # 提示词统计 + total_prompts = Prompt.query.count() + today_prompts = Prompt.query.filter( + Prompt.created_at >= datetime.now().date() + ).count() + + # 模板统计 + total_templates = PromptTemplate.query.count() + default_templates = PromptTemplate.query.filter_by(is_default=True).count() + + stats = { + 'total_users': total_users, + 'active_users': active_users, + 'total_prompts': total_prompts, + 'today_prompts': today_prompts, + 'total_templates': total_templates, + 'default_templates': default_templates + } + except Exception as e: + stats = { + 'total_users': 0, + 'active_users': 0, + 'total_prompts': 0, + 'today_prompts': 0, + 'total_templates': 0, + 'default_templates': 0 + } + + return self.render('admin/index.html', stats=stats) diff --git a/src/flask_prompt_master/admin/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/admin/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..967bc0f Binary files /dev/null and b/src/flask_prompt_master/admin/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/forms/__init__.py b/src/flask_prompt_master/admin/forms/__init__.py new file mode 100644 index 0000000..8452024 --- /dev/null +++ b/src/flask_prompt_master/admin/forms/__init__.py @@ -0,0 +1,6 @@ +""" +后台管理表单包 +""" +from .admin_forms import AdminLoginForm, AdminUserForm + +__all__ = ['AdminLoginForm', 'AdminUserForm'] diff --git a/src/flask_prompt_master/admin/forms/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/admin/forms/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..e3ad3dd Binary files /dev/null and b/src/flask_prompt_master/admin/forms/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/forms/__pycache__/admin_forms.cpython-312.pyc b/src/flask_prompt_master/admin/forms/__pycache__/admin_forms.cpython-312.pyc new file mode 100644 index 0000000..544b940 Binary files /dev/null and b/src/flask_prompt_master/admin/forms/__pycache__/admin_forms.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/forms/admin_forms.py b/src/flask_prompt_master/admin/forms/admin_forms.py new file mode 100644 index 0000000..36c64b8 --- /dev/null +++ b/src/flask_prompt_master/admin/forms/admin_forms.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +""" +后台管理表单 +""" +from flask_wtf import FlaskForm +from wtforms import StringField, PasswordField, BooleanField, SelectField, TextAreaField +from wtforms.validators import DataRequired, Email, Length, EqualTo, Optional + +class AdminLoginForm(FlaskForm): + """管理员登录表单""" + username = StringField('用户名', validators=[ + DataRequired(message='请输入用户名'), + Length(min=3, max=50, message='用户名长度必须在3-50个字符之间') + ]) + password = PasswordField('密码', validators=[ + DataRequired(message='请输入密码'), + Length(min=6, message='密码长度至少6位') + ]) + remember_me = BooleanField('记住我') + +class AdminUserForm(FlaskForm): + """管理员用户表单""" + username = StringField('用户名', validators=[ + DataRequired(message='请输入用户名'), + Length(min=3, max=50, message='用户名长度必须在3-50个字符之间') + ]) + email = StringField('邮箱', validators=[ + DataRequired(message='请输入邮箱'), + Email(message='邮箱格式不正确') + ]) + password = PasswordField('密码', validators=[ + Optional(), + Length(min=6, message='密码长度至少6位') + ]) + confirm_password = PasswordField('确认密码', validators=[ + Optional(), + EqualTo('password', message='两次输入的密码不一致') + ]) + role = SelectField('角色', choices=[ + ('super_admin', '超级管理员'), + ('user_admin', '用户管理员'), + ('content_admin', '内容管理员'), + ('system_admin', '系统管理员') + ], validators=[DataRequired(message='请选择角色')]) + is_active = BooleanField('是否激活', default=True) diff --git a/src/flask_prompt_master/admin/models/__init__.py b/src/flask_prompt_master/admin/models/__init__.py new file mode 100644 index 0000000..2da2468 --- /dev/null +++ b/src/flask_prompt_master/admin/models/__init__.py @@ -0,0 +1,6 @@ +""" +后台管理模型包 +""" +from .admin_user import AdminUser + +__all__ = ['AdminUser'] diff --git a/src/flask_prompt_master/admin/models/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/admin/models/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..ca64ac5 Binary files /dev/null and b/src/flask_prompt_master/admin/models/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/models/__pycache__/admin_user.cpython-312.pyc b/src/flask_prompt_master/admin/models/__pycache__/admin_user.cpython-312.pyc new file mode 100644 index 0000000..61adfde Binary files /dev/null and b/src/flask_prompt_master/admin/models/__pycache__/admin_user.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/models/admin_user.py b/src/flask_prompt_master/admin/models/admin_user.py new file mode 100644 index 0000000..5ce59e8 --- /dev/null +++ b/src/flask_prompt_master/admin/models/admin_user.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +""" +管理员用户模型 +""" +from datetime import datetime +from flask_login import UserMixin +from src.flask_prompt_master import db +import hashlib +import os + +class AdminUser(db.Model, UserMixin): + """管理员用户表""" + __tablename__ = 'admin_user' + + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String(50), unique=True, nullable=False, comment='用户名') + password_hash = db.Column(db.String(128), nullable=False, comment='密码哈希') + email = db.Column(db.String(100), unique=True, nullable=False, comment='邮箱') + role = db.Column(db.String(20), nullable=False, default='admin', comment='角色') + is_active = db.Column(db.Boolean, default=True, comment='是否激活') + last_login = db.Column(db.DateTime, comment='最后登录时间') + created_at = db.Column(db.DateTime, default=datetime.utcnow, comment='创建时间') + updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, comment='更新时间') + + def __init__(self, username, password, email, role='admin'): + self.username = username + self.password_hash = self._hash_password(password) + self.email = email + self.role = role + + def _hash_password(self, password): + """密码加密""" + salt = os.urandom(16).hex() + return hashlib.sha256((password + salt).encode()).hexdigest() + ':' + salt + + def check_password(self, password): + """验证密码""" + if ':' not in self.password_hash: + return False + hash_part, salt = self.password_hash.split(':') + return hashlib.sha256((password + salt).encode()).hexdigest() == hash_part + + def get_id(self): + """获取用户ID""" + return str(self.id) + + @property + def is_authenticated(self): + """是否已认证""" + return True + + @property + def is_anonymous(self): + """是否匿名用户""" + return False + + def __repr__(self): + return f'' diff --git a/src/flask_prompt_master/admin/views/__init__.py b/src/flask_prompt_master/admin/views/__init__.py new file mode 100644 index 0000000..060878a --- /dev/null +++ b/src/flask_prompt_master/admin/views/__init__.py @@ -0,0 +1,14 @@ +""" +后台管理视图包 +""" +from .user_admin import UserAdminView +from .prompt_admin import PromptAdminView +from .template_admin import TemplateAdminView +from .system_admin import SystemAdminView + +__all__ = [ + 'UserAdminView', + 'PromptAdminView', + 'TemplateAdminView', + 'SystemAdminView' +] diff --git a/src/flask_prompt_master/admin/views/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..79463ea Binary files /dev/null and b/src/flask_prompt_master/admin/views/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/__pycache__/prompt_admin.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/prompt_admin.cpython-312.pyc new file mode 100644 index 0000000..4585b44 Binary files /dev/null and b/src/flask_prompt_master/admin/views/__pycache__/prompt_admin.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/__pycache__/system_admin.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/system_admin.cpython-312.pyc new file mode 100644 index 0000000..c787c71 Binary files /dev/null and b/src/flask_prompt_master/admin/views/__pycache__/system_admin.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/__pycache__/template_admin.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/template_admin.cpython-312.pyc new file mode 100644 index 0000000..078a7ce Binary files /dev/null and b/src/flask_prompt_master/admin/views/__pycache__/template_admin.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/__pycache__/user_admin.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/user_admin.cpython-312.pyc new file mode 100644 index 0000000..b20420f Binary files /dev/null and b/src/flask_prompt_master/admin/views/__pycache__/user_admin.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/prompt_admin.py b/src/flask_prompt_master/admin/views/prompt_admin.py new file mode 100644 index 0000000..dba4bb1 --- /dev/null +++ b/src/flask_prompt_master/admin/views/prompt_admin.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +""" +提示词管理视图 +""" +from flask_admin.contrib.sqla import ModelView +from flask_login import current_user +from src.flask_prompt_master.models.models import Prompt +from datetime import datetime + +class PromptAdminView(ModelView): + """提示词管理视图""" + + # 设置模型 + model = Prompt + + # 设置页面标题 + name = '提示词管理' + endpoint = 'admin.prompt' + + # 设置列显示 + column_list = ['id', 'input_text', 'generated_text', 'user_id', 'created_at'] + column_labels = { + 'id': 'ID', + 'input_text': '输入文本', + 'generated_text': '生成文本', + 'user_id': '用户ID', + 'created_at': '创建时间' + } + + # 设置搜索 + column_searchable_list = ['input_text', 'generated_text'] + + # 设置过滤 + column_filters = ['created_at', 'user_id'] + + # 设置排序 + column_default_sort = ('created_at', True) + + # 设置编辑权限 + can_create = False + can_edit = True + can_delete = True + + # 设置表单字段 + form_excluded_columns = ['feedbacks'] + + # 设置文本字段为文本区域 + form_widget_args = { + 'input_text': {'rows': 3}, + 'generated_text': {'rows': 5} + } + + def is_accessible(self): + """检查访问权限""" + return current_user.is_authenticated and current_user.role in ['super_admin', 'content_admin'] + + def on_model_change(self, form, model, is_created): + """模型变更时的处理""" + # 可以添加内容审核逻辑 + pass diff --git a/src/flask_prompt_master/admin/views/system_admin.py b/src/flask_prompt_master/admin/views/system_admin.py new file mode 100644 index 0000000..6619452 --- /dev/null +++ b/src/flask_prompt_master/admin/views/system_admin.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- +""" +系统管理视图 +""" +from flask_admin import BaseView, expose +from flask_login import login_required, current_user +from src.flask_prompt_master.models.models import User, Prompt, PromptTemplate +from src.flask_prompt_master import db +from sqlalchemy import func +from datetime import datetime, timedelta + +class SystemAdminView(BaseView): + """系统管理视图""" + + @expose('/') + @login_required + def index(self): + """系统概览""" + if not current_user.is_authenticated or current_user.role not in ['super_admin', 'system_admin']: + return self.render('admin/403.html') + + # 获取统计数据 + stats = self._get_system_stats() + + return self.render('admin/system_dashboard.html', stats=stats) + + @expose('/logs') + @login_required + def logs(self): + """系统日志""" + if not current_user.is_authenticated or current_user.role not in ['super_admin', 'system_admin']: + return self.render('admin/403.html') + + # 这里可以添加日志查看功能 + return self.render('admin/system_logs.html') + + def _get_system_stats(self): + """获取系统统计信息""" + try: + # 用户统计 + total_users = User.query.count() + active_users = User.query.filter_by(status=1).count() + + # 提示词统计 + total_prompts = Prompt.query.count() + today_prompts = Prompt.query.filter( + Prompt.created_at >= datetime.now().date() + ).count() + + # 模板统计 + total_templates = PromptTemplate.query.count() + default_templates = PromptTemplate.query.filter_by(is_default=True).count() + + # 最近7天用户注册趋势 + seven_days_ago = datetime.now() - timedelta(days=7) + daily_registrations = db.session.query( + func.date(User.created_time).label('date'), + func.count(User.uid).label('count') + ).filter( + User.created_time >= seven_days_ago + ).group_by( + func.date(User.created_time) + ).all() + + return { + 'total_users': total_users, + 'active_users': active_users, + 'total_prompts': total_prompts, + 'today_prompts': today_prompts, + 'total_templates': total_templates, + 'default_templates': default_templates, + 'daily_registrations': daily_registrations + } + except Exception as e: + return { + 'total_users': 0, + 'active_users': 0, + 'total_prompts': 0, + 'today_prompts': 0, + 'total_templates': 0, + 'default_templates': 0, + 'daily_registrations': [] + } diff --git a/src/flask_prompt_master/admin/views/template_admin.py b/src/flask_prompt_master/admin/views/template_admin.py new file mode 100644 index 0000000..4c05e95 --- /dev/null +++ b/src/flask_prompt_master/admin/views/template_admin.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +""" +模板管理视图 +""" +from flask_admin.contrib.sqla import ModelView +from flask_login import current_user +from src.flask_prompt_master.models.models import PromptTemplate +from datetime import datetime + +class TemplateAdminView(ModelView): + """模板管理视图""" + + # 设置模型 + model = PromptTemplate + + # 设置页面标题 + name = '模板管理' + endpoint = 'admin.template' + + # 设置列显示 + column_list = ['id', 'name', 'category', 'industry', 'profession', 'is_default', 'created_at'] + column_labels = { + 'id': 'ID', + 'name': '模板名称', + 'category': '分类', + 'industry': '行业', + 'profession': '职业', + 'is_default': '是否默认', + 'created_at': '创建时间' + } + + # 设置搜索 + column_searchable_list = ['name', 'category', 'industry', 'profession'] + + # 设置过滤 + column_filters = ['category', 'industry', 'profession', 'is_default', 'created_at'] + + # 设置排序 + column_default_sort = ('created_at', True) + + # 设置编辑权限 + can_create = True + can_edit = True + can_delete = True + + # 设置表单字段 + form_excluded_columns = ['updated_at'] + + # 设置文本字段为文本区域 + form_widget_args = { + 'description': {'rows': 3}, + 'system_prompt': {'rows': 8} + } + + def is_accessible(self): + """检查访问权限""" + return current_user.is_authenticated and current_user.role in ['super_admin', 'content_admin'] + + def on_model_change(self, form, model, is_created): + """模型变更时的处理""" + if is_created: + model.created_at = datetime.now() + model.updated_at = datetime.now() diff --git a/src/flask_prompt_master/admin/views/user_admin.py b/src/flask_prompt_master/admin/views/user_admin.py new file mode 100644 index 0000000..8c7b8c7 --- /dev/null +++ b/src/flask_prompt_master/admin/views/user_admin.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +""" +用户管理视图 +""" +from flask_admin import BaseView, expose +from flask_admin.contrib.sqla import ModelView +from flask_login import login_required, current_user +from src.flask_prompt_master.models.models import User +from src.flask_prompt_master import db +from datetime import datetime + +class UserAdminView(ModelView): + """用户管理视图""" + + # 设置模型 + model = User + + # 设置页面标题 + name = '用户管理' + endpoint = 'admin.user' + + # 设置列显示 + column_list = ['uid', 'nickname', 'login_name', 'email', 'mobile', 'sex', 'status', 'created_time'] + column_labels = { + 'uid': '用户ID', + 'nickname': '昵称', + 'login_name': '用户名', + 'email': '邮箱', + 'mobile': '手机号', + 'sex': '性别', + 'status': '状态', + 'created_time': '注册时间' + } + + # 设置搜索 + column_searchable_list = ['nickname', 'login_name', 'email', 'mobile'] + + # 设置过滤 + column_filters = ['status', 'sex', 'created_time'] + + # 设置排序 + column_default_sort = ('created_time', True) + + # 设置编辑权限 + can_create = False + can_edit = True + can_delete = True + + # 设置表单字段 + form_excluded_columns = ['login_pwd', 'login_salt', 'prompts', 'feedbacks'] + + def is_accessible(self): + """检查访问权限""" + return current_user.is_authenticated and current_user.role in ['super_admin', 'user_admin'] + + def on_model_change(self, form, model, is_created): + """模型变更时的处理""" + if not is_created: + model.updated_time = datetime.now() + + def after_model_delete(self, model): + """删除模型后的处理""" + # 记录删除日志 + pass diff --git a/src/flask_prompt_master/models/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/models/__pycache__/__init__.cpython-312.pyc index 531e32d..2829091 100644 Binary files a/src/flask_prompt_master/models/__pycache__/__init__.cpython-312.pyc and b/src/flask_prompt_master/models/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/models/__pycache__/favorites.cpython-312.pyc b/src/flask_prompt_master/models/__pycache__/favorites.cpython-312.pyc index d967b66..40bdd3c 100644 Binary files a/src/flask_prompt_master/models/__pycache__/favorites.cpython-312.pyc and b/src/flask_prompt_master/models/__pycache__/favorites.cpython-312.pyc differ diff --git a/src/flask_prompt_master/models/__pycache__/models.cpython-312.pyc b/src/flask_prompt_master/models/__pycache__/models.cpython-312.pyc index b7b3367..f12ac2b 100644 Binary files a/src/flask_prompt_master/models/__pycache__/models.cpython-312.pyc and b/src/flask_prompt_master/models/__pycache__/models.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/auth.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/auth.cpython-312.pyc index 1452559..06641fa 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/auth.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/auth.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/favorites.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/favorites.cpython-312.pyc index 285bc9b..1a87442 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/favorites.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/favorites.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/routes.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/routes.cpython-312.pyc index 9084971..b091354 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/routes.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/routes.cpython-312.pyc differ diff --git a/src/flask_prompt_master/services/__pycache__/auth_service.cpython-312.pyc b/src/flask_prompt_master/services/__pycache__/auth_service.cpython-312.pyc index b04567a..f550266 100644 Binary files a/src/flask_prompt_master/services/__pycache__/auth_service.cpython-312.pyc and b/src/flask_prompt_master/services/__pycache__/auth_service.cpython-312.pyc differ diff --git a/src/flask_prompt_master/services/__pycache__/favorite_service.cpython-312.pyc b/src/flask_prompt_master/services/__pycache__/favorite_service.cpython-312.pyc index bac5462..6a23bf4 100644 Binary files a/src/flask_prompt_master/services/__pycache__/favorite_service.cpython-312.pyc and b/src/flask_prompt_master/services/__pycache__/favorite_service.cpython-312.pyc differ diff --git a/src/flask_prompt_master/templates/admin/index.html b/src/flask_prompt_master/templates/admin/index.html new file mode 100644 index 0000000..f5497de --- /dev/null +++ b/src/flask_prompt_master/templates/admin/index.html @@ -0,0 +1,116 @@ +{% extends 'admin/master.html' %} + +{% block title %}管理后台首页{% endblock %} + +{% block body %} +
+
+
+

+ 系统概览 +

+
+
+ + +
+
+
+
+
+ 快速操作 +
+
+ +
+
+
+ + +
+
+
+
+
+ 系统信息 +
+
+
+
+
+ + + + + + + + + + + + + +
系统名称:提示词大师管理系统
当前用户:{{ current_user.username if current_user.is_authenticated else '未登录' }}
用户角色:{{ current_user.role if current_user.is_authenticated else '无' }}
+
+
+ + + + + + + + + + + + + +
最后登录:{{ current_user.last_login.strftime('%Y-%m-%d %H:%M:%S') if current_user.is_authenticated and current_user.last_login else '首次登录' }}
登录时间:{{ current_user.created_at.strftime('%Y-%m-%d %H:%M:%S') if current_user.is_authenticated else '无' }}
账户状态: + {% if current_user.is_authenticated %} + + {{ '正常' if current_user.is_active else '禁用' }} + + {% else %} + 未登录 + {% endif %} +
+
+
+
+
+
+
+
+ + +{% endblock %} diff --git a/src/flask_prompt_master/templates/admin/login.html b/src/flask_prompt_master/templates/admin/login.html new file mode 100644 index 0000000..7f8fbb4 --- /dev/null +++ b/src/flask_prompt_master/templates/admin/login.html @@ -0,0 +1,137 @@ + + + + + + 管理员登录 - 提示词大师后台管理 + + + + + +
+ + + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + +
+ {{ form.hidden_tag() }} + +
+ + {{ form.username(class="form-control", placeholder="请输入用户名") }} + {% if form.username.errors %} +
+ {% for error in form.username.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} +
+ +
+ + {{ form.password(class="form-control", placeholder="请输入密码") }} + {% if form.password.errors %} +
+ {% for error in form.password.errors %} + {{ error }} + {% endfor %} +
+ {% endif %} +
+ +
+ {{ form.remember_me(class="form-check-input") }} + +
+ +
+ +
+
+ + +
+ + + + diff --git a/src/flask_prompt_master/templates/admin/system_dashboard.html b/src/flask_prompt_master/templates/admin/system_dashboard.html new file mode 100644 index 0000000..c867874 --- /dev/null +++ b/src/flask_prompt_master/templates/admin/system_dashboard.html @@ -0,0 +1,223 @@ +{% extends 'admin/master.html' %} + +{% block title %}系统管理 - 仪表板{% endblock %} + +{% block body %} +
+
+
+

+ 系统仪表板 +

+
+
+ + +
+
+
+
+
+
+
+ 总用户数 +
+
{{ stats.total_users }}
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+ 今日生成 +
+
{{ stats.today_prompts }}
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+ 模板数量 +
+
{{ stats.total_templates }}
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+ 活跃用户 +
+
{{ stats.active_users }}
+
+
+ +
+
+
+
+
+
+ + +
+
+
+
+
+ 系统信息 +
+
+
+
+
+ + + + + + + + + + + + + + + + + +
系统名称:提示词大师管理系统
当前用户:{{ current_user.username if current_user.is_authenticated else '未登录' }}
用户角色:{{ current_user.role if current_user.is_authenticated else '无' }}
系统状态:正常运行
+
+
+ + + + + + + + + + + + + + + + + +
最后登录:{{ current_user.last_login.strftime('%Y-%m-%d %H:%M:%S') if current_user.is_authenticated and current_user.last_login else '首次登录' }}
登录时间:{{ current_user.created_at.strftime('%Y-%m-%d %H:%M:%S') if current_user.is_authenticated else '无' }}
账户状态: + {% if current_user.is_authenticated %} + + {{ '正常' if current_user.is_active else '禁用' }} + + {% else %} + 未登录 + {% endif %} +
数据库状态:连接正常
+
+
+
+
+
+
+ + +
+
+
+
+
+ 快速操作 +
+
+ +
+
+
+
+ + +{% endblock %} diff --git a/src/flask_prompt_master/templates/admin/system_logs.html b/src/flask_prompt_master/templates/admin/system_logs.html new file mode 100644 index 0000000..8d54380 --- /dev/null +++ b/src/flask_prompt_master/templates/admin/system_logs.html @@ -0,0 +1,86 @@ +{% extends 'admin/master.html' %} + +{% block title %}系统日志{% endblock %} + +{% block body %} +
+
+
+

+ 系统日志 +

+
+
+ +
+
+
+
+
+ 日志列表 +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
时间级别模块消息操作
2025-08-29 22:34:44INFO系统管理管理员登录成功 + +
2025-08-29 22:33:42SUCCESS应用启动Flask应用启动成功 + +
2025-08-29 22:33:42INFO数据库数据库连接成功 + +
+
+
+
+
+
+
+ + +{% endblock %}