初始化技术博客项目

功能特性:
- 前端文章展示 (Markdown渲染、代码高亮)
- 后台管理系统 (文章、分类、标签、作者管理)
- 图片上传 (点击、拖拽、粘贴)
- 网站设置 (Logo、底部宣传图片上传)
- 访问统计 (IP记录、趋势图表)
- 参考来源、附件支持
- 单端口部署 (16012)

技术栈:
- Flask 3.0 + SQLAlchemy
- SQLite数据库
- marked.js + highlight.js (Markdown渲染)
- Chart.js (统计图表)
This commit is contained in:
2026-06-04 23:12:34 +08:00
commit e689fed71e
53 changed files with 6506 additions and 0 deletions

83
app/models/visit_log.py Normal file
View File

@@ -0,0 +1,83 @@
"""访问统计模型"""
from datetime import datetime
from app import db
class VisitLog(db.Model):
"""访问日志表"""
__tablename__ = 'visit_logs'
id = db.Column(db.Integer, primary_key=True)
# 访问信息
ip_address = db.Column(db.String(50), nullable=False)
user_agent = db.Column(db.String(500))
referer = db.Column(db.String(500))
# 访问路径
path = db.Column(db.String(500), nullable=False)
method = db.Column(db.String(10), default='GET')
# 访问者信息可从IP解析
country = db.Column(db.String(50))
city = db.Column(db.String(50))
# 文章关联(如果访问的是文章详情页)
article_id = db.Column(db.Integer, db.ForeignKey('articles.id'))
article = db.relationship('Article', backref='visit_logs')
# 时间戳
visited_at = db.Column(db.DateTime, default=datetime.utcnow, index=True)
def __repr__(self):
return f'<VisitLog {self.ip_address} - {self.path}>'
@staticmethod
def get_today_count():
"""获取今日访问量"""
from datetime import date
today = date.today()
return VisitLog.query.filter(
VisitLog.visited_at >= datetime.combine(today, datetime.min.time())
).count()
@staticmethod
def get_total_count():
"""获取总访问量"""
return VisitLog.query.count()
@staticmethod
def get_unique_ip_count():
"""获取独立IP数量"""
return db.session.query(db.func.count(db.func.distinct(VisitLog.ip_address))).scalar()
class DailyStats(db.Model):
"""每日统计汇总表"""
__tablename__ = 'daily_stats'
id = db.Column(db.Integer, primary_key=True)
date = db.Column(db.Date, unique=True, nullable=False, index=True)
# 统计数据
total_visits = db.Column(db.Integer, default=0)
unique_ips = db.Column(db.Integer, default=0)
article_views = db.Column(db.Integer, default=0)
# 热门文章
top_article_id = db.Column(db.Integer, db.ForeignKey('articles.id'))
top_article_views = db.Column(db.Integer, default=0)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def __repr__(self):
return f'<DailyStats {self.date}>'
@staticmethod
def get_stats_list(days=30):
"""获取最近N天的统计数据"""
from datetime import date, timedelta
start_date = date.today() - timedelta(days=days)
return DailyStats.query.filter(
DailyStats.date >= start_date
).order_by(DailyStats.date.desc()).all()