feat(历史记录): 添加历史记录查询功能及PDF导出

新增历史记录查询页面,支持按时间范围筛选阅读记录、感悟记录、汇总记录、家庭事项和今日计划
添加历史记录PDF导出功能,生成包含所有记录的格式化PDF报告
This commit is contained in:
2026-02-01 18:24:18 +08:00
parent 4c562897f4
commit d0fa855388
5 changed files with 885 additions and 0 deletions

150
core/history_views.py Normal file
View File

@@ -0,0 +1,150 @@
from django.shortcuts import render
from django.http import HttpResponse
from django.utils import timezone
from django.contrib.auth.decorators import login_required
from django.conf import settings
from datetime import datetime, timedelta
from loguru import logger
import os
from .models import (
ReadingRecord,
InsightRecord,
Summary,
FamilyTask,
TodayPlan,
)
from .views import is_weasyprint_available
@login_required
def history_records(request):
"""历史记录查询页面"""
logger.info("用户访问历史记录查询页面")
start_date_str = request.GET.get('start_date')
end_date_str = request.GET.get('end_date')
if not start_date_str or not end_date_str:
today = timezone.now().date()
start_date = datetime(today.year, 1, 1).date()
end_date = today
else:
start_date = datetime.strptime(start_date_str, '%Y-%m-%d').date()
end_date = datetime.strptime(end_date_str, '%Y-%m-%d').date()
# 查询各个类型的记录
reading_records = ReadingRecord.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
insight_records = InsightRecord.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
summary_records = Summary.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
family_tasks = FamilyTask.objects.filter(
created_at__date__range=[start_date, end_date]
).order_by('-created_at')
today_plans = TodayPlan.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
context = {
'start_date': start_date,
'end_date': end_date,
'reading_records': reading_records,
'insight_records': insight_records,
'summary_records': summary_records,
'family_tasks': family_tasks,
'today_plans': today_plans,
}
return render(request, 'core/history_records.html', context)
@login_required
def history_pdf(request):
"""导出历史记录PDF"""
if not is_weasyprint_available():
logger.error("WeasyPrint库不可用无法生成PDF报告")
return HttpResponse("PDF功能不可用请检查WeasyPrint库是否正确安装", status=500)
start_date_str = request.GET.get('start_date')
end_date_str = request.GET.get('end_date')
if not start_date_str or not end_date_str:
return HttpResponse("请提供开始时间和结束时间", status=400)
try:
start_date = datetime.strptime(start_date_str, '%Y-%m-%d').date()
end_date = datetime.strptime(end_date_str, '%Y-%m-%d').date()
except ValueError:
return HttpResponse("日期格式错误", status=400)
if start_date > end_date:
return HttpResponse("开始时间不能晚于结束时间", status=400)
logger.info(f"用户导出历史记录PDF: {start_date}{end_date}")
try:
# 查询各个类型的记录
reading_records = ReadingRecord.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
insight_records = InsightRecord.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
summary_records = Summary.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
family_tasks = FamilyTask.objects.filter(
created_at__date__range=[start_date, end_date]
).order_by('-created_at')
today_plans = TodayPlan.objects.filter(
date__range=[start_date, end_date]
).order_by('-date')
context = {
'start_date': start_date,
'end_date': end_date,
'reading_records': reading_records,
'insight_records': insight_records,
'summary_records': summary_records,
'family_tasks': family_tasks,
'today_plans': today_plans,
}
# 渲染HTML模板
html_string = render(request, 'core/history_pdf.html', context).content.decode('utf-8')
# 生成PDF
pdf_file = f"history_{start_date_str}_to_{end_date_str}.pdf"
pdf_path = os.path.join(settings.REPORTS_ROOT, pdf_file)
# 确保报告目录存在
os.makedirs(settings.REPORTS_ROOT, exist_ok=True)
# 动态导入WeasyPrint
from weasyprint import HTML
HTML(string=html_string).write_pdf(pdf_path)
logger.info(f"历史记录PDF生成成功: {pdf_path}")
# 返回PDF文件
with open(pdf_path, 'rb') as f:
response = HttpResponse(f.read(), content_type='application/pdf')
response['Content-Disposition'] = f'attachment; filename="{pdf_file}"'
return response
except Exception as e:
logger.error(f"生成历史记录PDF失败: {str(e)}")
return HttpResponse(f"生成PDF失败: {str(e)}", status=500)

View File

@@ -0,0 +1,344 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>历史记录 - {{ start_date|date:"Y-m-d" }} 至 {{ end_date|date:"Y-m-d" }}</title>
<style>
@page {
size: A4;
margin: 1.5cm;
}
body {
font-family: "Microsoft YaHei", "SimHei", sans-serif;
font-size: 12pt;
line-height: 1.6;
color: #333;
}
.header {
text-align: center;
border-bottom: 3px solid #2c3e50;
padding-bottom: 15px;
margin-bottom: 30px;
}
.header h1 {
color: #2c3e50;
font-size: 24pt;
margin: 0 0 10px 0;
}
.header .date-range {
color: #666;
font-size: 14pt;
}
.section {
margin-bottom: 30px;
page-break-inside: avoid;
}
.section-title {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 10px 15px;
font-size: 14pt;
font-weight: bold;
border-radius: 5px;
margin-bottom: 15px;
}
.section-title.reading { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
.section-title.insight { background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%); }
.section-title.summary { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); }
.section-title.task { background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); }
.section-title.plan { background: linear-gradient(135deg, #8e9eab 0%, #eef2f3 100%); color: #333; }
.record-item {
background: #f8f9fa;
border-left: 4px solid #667eea;
padding: 12px 15px;
margin-bottom: 12px;
border-radius: 0 5px 5px 0;
}
.record-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
flex-wrap: wrap;
}
.record-date {
background: #667eea;
color: white;
padding: 3px 10px;
border-radius: 12px;
font-size: 10pt;
}
.record-meta {
color: #666;
font-size: 10pt;
}
.record-content {
margin-top: 8px;
}
.record-content p {
margin: 0 0 8px 0;
}
.badge {
display: inline-block;
padding: 2px 8px;
border-radius: 10px;
font-size: 9pt;
margin-right: 5px;
}
.badge-primary { background: #667eea; color: white; }
.badge-secondary { background: #6c757d; color: white; }
.badge-success { background: #28a745; color: white; }
.badge-warning { background: #ffc107; color: #333; }
.badge-info { background: #17a2b8; color: white; }
.badge-danger { background: #dc3545; color: white; }
.empty-notice {
text-align: center;
color: #999;
font-style: italic;
padding: 20px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
th, td {
border: 1px solid #dee2e6;
padding: 8px 12px;
text-align: left;
font-size: 10pt;
}
th {
background: #f8f9fa;
font-weight: bold;
}
tr:nth-child(even) {
background: #f8f9fa;
}
.progress-bar {
background: #e9ecef;
border-radius: 10px;
height: 8px;
width: 100px;
display: inline-block;
}
.progress-fill {
background: #667eea;
height: 100%;
border-radius: 10px;
}
.footer {
margin-top: 40px;
padding-top: 15px;
border-top: 1px solid #dee2e6;
text-align: center;
color: #999;
font-size: 10pt;
}
</style>
</head>
<body>
<div class="header">
<h1>历史记录汇总</h1>
<div class="date-range">
{{ start_date|date:"Y年m月d日" }} 至 {{ end_date|date:"Y年m月d日" }}
</div>
</div>
<!-- 阅读记录 -->
<div class="section">
<div class="section-title reading">阅读记录 ({{ reading_records|length }} 条)</div>
{% if reading_records %}
<table>
<thead>
<tr>
<th>日期</th>
<th>类型</th>
<th>标题</th>
<th>来源</th>
<th>进度</th>
</tr>
</thead>
<tbody>
{% for record in reading_records %}
<tr>
<td>{{ record.date|date:"Y-m-d" }}</td>
<td><span class="badge badge-info">{{ record.type.name }}</span></td>
<td>{{ record.title }}</td>
<td>{{ record.source|default:"-" }}</td>
<td>
{% if record.progress %}
<div class="progress-bar">
<div class="progress-fill" style="width: {{ record.progress }}%"></div>
</div>
<small>{{ record.progress }}%</small>
{% else %}
-
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="empty-notice">该时间段没有阅读记录</div>
{% endif %}
</div>
<!-- 感悟记录 -->
<div class="section">
<div class="section-title insight">感悟记录 ({{ insight_records|length }} 条)</div>
{% if insight_records %}
{% for record in insight_records %}
<div class="record-item">
<div class="record-header">
<span class="record-date">{{ record.date|date:"Y-m-d" }}</span>
<span class="record-meta">发言人: {{ record.speaker.name }}</span>
</div>
<div class="record-content">
{{ record.content|linebreaks }}
</div>
</div>
{% endfor %}
{% else %}
<div class="empty-notice">该时间段没有感悟记录</div>
{% endif %}
</div>
<!-- 汇总记录 -->
<div class="section">
<div class="section-title summary">汇总记录 ({{ summary_records|length }} 条)</div>
{% if summary_records %}
{% for record in summary_records %}
<div class="record-item">
<div class="record-header">
<span class="record-date">{{ record.date|date:"Y-m-d" }}</span>
<span class="record-meta">
<span class="badge badge-secondary">{{ record.category.name }}</span>
发言人: {{ record.speaker.name }}
</span>
</div>
<div class="record-content">
{{ record.content|linebreaks }}
{% if record.source %}
<p><small>来源: {{ record.source }}</small></p>
{% endif %}
</div>
</div>
{% endfor %}
{% else %}
<div class="empty-notice">该时间段没有汇总记录</div>
{% endif %}
</div>
<!-- 家庭事项 -->
<div class="section">
<div class="section-title task">家庭事项 ({{ family_tasks|length }} 条)</div>
{% if family_tasks %}
<table>
<thead>
<tr>
<th>创建时间</th>
<th>类型</th>
<th>内容</th>
<th>优先级</th>
<th>状态</th>
<th>截止日期</th>
</tr>
</thead>
<tbody>
{% for task in family_tasks %}
<tr>
<td>{{ task.created_at|date:"Y-m-d H:i" }}</td>
<td><span class="badge badge-secondary">{{ task.type.name }}</span></td>
<td>{{ task.content|truncatechars:50 }}</td>
<td>
<span class="badge {% if task.priority.name == '高' %}badge-danger{% elif task.priority.name == '中' %}badge-warning{% else %}badge-info{% endif %}">
{{ task.priority.name }}
</span>
</td>
<td>
<span class="badge {% if task.status.name == 'completed' %}badge-success{% else %}badge-warning{% endif %}">
{{ task.status.name }}
</span>
</td>
<td>{{ task.deadline|date:"Y-m-d"|default:"-" }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="empty-notice">该时间段没有家庭事项</div>
{% endif %}
</div>
<!-- 今日计划 -->
<div class="section">
<div class="section-title plan">今日计划 ({{ today_plans|length }} 条)</div>
{% if today_plans %}
<table>
<thead>
<tr>
<th>日期</th>
<th>发言人</th>
<th>内容</th>
<th>类型</th>
<th>优先级</th>
<th>状态</th>
</tr>
</thead>
<tbody>
{% for plan in today_plans %}
<tr>
<td>{{ plan.date|date:"Y-m-d" }}</td>
<td>{{ plan.speaker.name }}</td>
<td>{{ plan.content|truncatechars:50 }}</td>
<td><span class="badge badge-info">{{ plan.type.name }}</span></td>
<td>
<span class="badge {% if plan.priority.name == '高' %}badge-danger{% elif plan.priority.name == '中' %}badge-warning{% else %}badge-info{% endif %}">
{{ plan.priority.name }}
</span>
</td>
<td>
<span class="badge {% if plan.status.name == 'completed' %}badge-success{% else %}badge-warning{% endif %}">
{{ plan.status.name }}
</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="empty-notice">该时间段没有今日计划</div>
{% endif %}
</div>
<div class="footer">
<p>家庭日报系统 - 历史记录导出</p>
<p>生成时间: {% now "Y-m-d H:i:s" %}</p>
</div>
</body>
</html>

View File

@@ -0,0 +1,293 @@
{% extends 'core/base.html' %}
{% block content %}
<!-- 页面标题 -->
<div class="row mb-4">
<div class="col-12">
<div class="card" style="background: linear-gradient(135deg, #2c3e50 0%, #4ca1af 100%); color: white;">
<div class="card-body d-flex align-items-center justify-content-between py-4">
<div>
<h3 class="mb-1"><i class="bi bi-clock-history me-2"></i>历史记录查询</h3>
<p class="mb-0 opacity-75">
<i class="bi bi-calendar-range me-2"></i>
{{ start_date|date:"Y年m月d日" }} 至 {{ end_date|date:"Y年m月d日" }}
</p>
</div>
<div class="text-end d-none d-md-block">
<i class="bi bi-archive" style="font-size: 4rem; opacity: 0.3;"></i>
</div>
</div>
</div>
</div>
</div>
<!-- 阅读记录 -->
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0"><i class="bi bi-book me-2"></i>阅读记录</h5>
<span class="badge bg-light text-primary">{{ reading_records|length }} 条</span>
</div>
<div class="card-body">
{% if reading_records %}
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>日期</th>
<th>类型</th>
<th>标题</th>
<th>来源</th>
<th>进度</th>
</tr>
</thead>
<tbody>
{% for record in reading_records %}
<tr>
<td>{{ record.date|date:"Y-m-d" }}</td>
<td><span class="badge bg-info">{{ record.type.name }}</span></td>
<td>{{ record.title }}</td>
<td>{{ record.source|default:"-" }}</td>
<td>
{% if record.progress %}
<div class="progress" style="height: 6px; width: 100px;">
<div class="progress-bar bg-primary" role="progressbar" style="width: {{ record.progress }}%"></div>
</div>
<small class="text-muted">{{ record.progress }}%</small>
{% else %}
-
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-4">
<i class="bi bi-inbox text-muted" style="font-size: 3rem;"></i>
<p class="text-muted mt-2">该时间段没有阅读记录</p>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<!-- 感悟记录 -->
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-header bg-success text-white d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0"><i class="bi bi-lightbulb me-2"></i>感悟记录</h5>
<span class="badge bg-light text-success">{{ insight_records|length }} 条</span>
</div>
<div class="card-body">
{% if insight_records %}
<div class="list-group">
{% for record in insight_records %}
<div class="list-group-item">
<div class="d-flex justify-content-between align-items-start mb-2">
<div>
<span class="badge bg-success me-2">{{ record.date|date:"Y-m-d" }}</span>
<span class="text-muted"><i class="bi bi-person me-1"></i>{{ record.speaker.name }}</span>
</div>
</div>
<p class="mb-2">{{ record.content|linebreaks }}</p>
{% if record.file %}
<a href="{{ record.file.url }}" class="file-link small" target="_blank">
<i class="bi bi-paperclip me-1"></i>查看附件
</a>
{% endif %}
</div>
{% endfor %}
</div>
{% else %}
<div class="text-center py-4">
<i class="bi bi-inbox text-muted" style="font-size: 3rem;"></i>
<p class="text-muted mt-2">该时间段没有感悟记录</p>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<!-- 汇总记录 -->
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-header bg-info text-white d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0"><i class="bi bi-collection me-2"></i>汇总记录</h5>
<span class="badge bg-light text-info">{{ summary_records|length }} 条</span>
</div>
<div class="card-body">
{% if summary_records %}
<div class="list-group">
{% for record in summary_records %}
<div class="list-group-item">
<div class="d-flex justify-content-between align-items-start mb-2">
<div>
<span class="badge bg-primary me-2">{{ record.date|date:"Y-m-d" }}</span>
<span class="badge bg-secondary me-2">{{ record.category.name }}</span>
<span class="text-muted"><i class="bi bi-person me-1"></i>{{ record.speaker.name }}</span>
</div>
</div>
<p class="mb-2">{{ record.content|linebreaks }}</p>
{% if record.source %}
<div class="small text-muted mb-2">
<i class="bi bi-link-45deg me-1"></i>{{ record.source }}
</div>
{% endif %}
{% if record.file %}
<a href="{{ record.file.url }}" class="file-link small" target="_blank">
<i class="bi bi-paperclip me-1"></i>查看附件
</a>
{% endif %}
</div>
{% endfor %}
</div>
{% else %}
<div class="text-center py-4">
<i class="bi bi-inbox text-muted" style="font-size: 3rem;"></i>
<p class="text-muted mt-2">该时间段没有汇总记录</p>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<!-- 家庭事项 -->
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-header bg-warning text-white d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0"><i class="bi bi-list-check me-2"></i>家庭事项</h5>
<span class="badge bg-light text-warning">{{ family_tasks|length }} 条</span>
</div>
<div class="card-body">
{% if family_tasks %}
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>创建时间</th>
<th>类型</th>
<th>内容</th>
<th>优先级</th>
<th>状态</th>
<th>截止日期</th>
</tr>
</thead>
<tbody>
{% for task in family_tasks %}
<tr>
<td>{{ task.created_at|date:"Y-m-d H:i" }}</td>
<td><span class="badge bg-secondary">{{ task.type.name }}</span></td>
<td>{{ task.content|truncatechars:50 }}</td>
<td>
<span class="badge {% if task.priority.name == '高' %}bg-danger{% elif task.priority.name == '中' %}bg-warning{% else %}bg-info{% endif %}">
{{ task.priority.name }}
</span>
</td>
<td>
<span class="badge {% if task.status.name == 'completed' %}bg-success{% else %}bg-warning{% endif %}">
{{ task.status.name }}
</span>
</td>
<td>
{% if task.deadline %}
{% if task.is_overdue %}
<span class="text-danger">{{ task.deadline|date:"Y-m-d" }} (已逾期)</span>
{% else %}
{{ task.deadline|date:"Y-m-d" }}
{% endif %}
{% else %}
-
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-4">
<i class="bi bi-inbox text-muted" style="font-size: 3rem;"></i>
<p class="text-muted mt-2">该时间段没有家庭事项</p>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<!-- 今日计划 -->
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-header bg-secondary text-white d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0"><i class="bi bi-calendar-check me-2"></i>今日计划</h5>
<span class="badge bg-light text-secondary">{{ today_plans|length }} 条</span>
</div>
<div class="card-body">
{% if today_plans %}
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>日期</th>
<th>发言人</th>
<th>内容</th>
<th>类型</th>
<th>优先级</th>
<th>状态</th>
</tr>
</thead>
<tbody>
{% for plan in today_plans %}
<tr>
<td>{{ plan.date|date:"Y-m-d" }}</td>
<td>{{ plan.speaker.name }}</td>
<td>{{ plan.content|truncatechars:50 }}</td>
<td><span class="badge bg-info">{{ plan.type.name }}</span></td>
<td>
<span class="badge {% if plan.priority.name == '高' %}bg-danger{% elif plan.priority.name == '中' %}bg-warning{% else %}bg-info{% endif %}">
{{ plan.priority.name }}
</span>
</td>
<td>
<span class="badge {% if plan.status.name == 'completed' %}bg-success{% else %}bg-warning{% endif %}">
{{ plan.status.name }}
</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-4">
<i class="bi bi-inbox text-muted" style="font-size: 3rem;"></i>
<p class="text-muted mt-2">该时间段没有今日计划</p>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<!-- 返回按钮 -->
<div class="row mb-4">
<div class="col-12">
<a href="{% url 'index' %}" class="btn btn-outline-secondary">
<i class="bi bi-arrow-left me-1"></i>返回首页
</a>
<a href="{% url 'history_pdf' %}?start_date={{ start_date|date:'Y-m-d' }}&end_date={{ end_date|date:'Y-m-d' }}" class="btn btn-success">
<i class="bi bi-file-earmark-pdf me-1"></i>导出PDF
</a>
</div>
</div>
{% endblock %}

View File

@@ -279,4 +279,97 @@
</div>
</div>
</div>
<!-- 历史记录查询 -->
<div class="row mt-4">
<div class="col-12">
<div class="card">
<div class="card-header bg-dark text-white d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0"><i class="bi bi-clock-history me-2"></i>历史记录查询</h5>
<span class="badge bg-light text-dark">导出PDF</span>
</div>
<div class="card-body">
<form id="historyForm" method="GET" action="{% url 'history_records' %}">
<div class="row align-items-end">
<div class="col-md-3">
<label class="form-label"><i class="bi bi-calendar-minus me-1"></i>开始时间</label>
<input type="date" class="form-control" id="start_date" name="start_date" required>
</div>
<div class="col-md-3">
<label class="form-label"><i class="bi bi-calendar-plus me-1"></i>结束时间</label>
<input type="date" class="form-control" id="end_date" name="end_date" required>
</div>
<div class="col-md-6">
<div class="d-flex gap-2 flex-wrap">
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="setCurrentQuarter()">
<i class="bi bi-calendar3 me-1"></i>当季
</button>
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="setCurrentYear()">
<i class="bi bi-calendar-year me-1"></i>本年度
</button>
<button type="submit" class="btn btn-primary">
<i class="bi bi-search me-1"></i>查询记录
</button>
<button type="button" class="btn btn-success" onclick="exportHistoryPDF()">
<i class="bi bi-file-earmark-pdf me-1"></i>导出PDF
</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<script>
// 设置当季时间范围最近3个月
function setCurrentQuarter() {
const today = new Date();
const threeMonthsAgo = new Date(today.getFullYear(), today.getMonth() - 2, 1);
document.getElementById('start_date').value = formatDate(threeMonthsAgo);
document.getElementById('end_date').value = formatDate(today);
}
// 设置本年度时间范围
function setCurrentYear() {
const today = new Date();
const yearStart = new Date(today.getFullYear(), 0, 1);
document.getElementById('start_date').value = formatDate(yearStart);
document.getElementById('end_date').value = formatDate(today);
}
// 格式化日期为 YYYY-MM-DD
function formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
// 导出历史记录PDF
function exportHistoryPDF() {
const startDate = document.getElementById('start_date').value;
const endDate = document.getElementById('end_date').value;
if (!startDate || !endDate) {
alert('请先选择开始时间和结束时间');
return;
}
if (new Date(startDate) > new Date(endDate)) {
alert('开始时间不能晚于结束时间');
return;
}
window.location.href = `{% url 'history_pdf' %}?start_date=${startDate}&end_date=${endDate}`;
}
// 页面加载时默认设置为本年度
document.addEventListener('DOMContentLoaded', function() {
setCurrentYear();
});
</script>
{% endblock %}

View File

@@ -1,5 +1,6 @@
from django.urls import path
from . import views
from . import history_views
urlpatterns = [
# 登录和注销
@@ -63,4 +64,8 @@ urlpatterns = [
# PDF文件列表
path('pdf-list/', views.pdf_list, name='pdf_list'),
# 历史记录查询
path('history/', history_views.history_records, name='history_records'),
path('history/pdf/', history_views.history_pdf, name='history_pdf'),
]