- 更新 .gitignore,忽略所有文档和临时文件 - 删除迁移痕迹文件(AI提示词、PRD文档等) - 更新 README.md,移除截图引用 - 只保留源代码用于开源发布 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
447 lines
28 KiB
HTML
447 lines
28 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Outlook 邮件管理</title>
|
||
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.8/dist/purify.min.js"></script>
|
||
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
|
||
</head>
|
||
|
||
<body>
|
||
<div id="app">
|
||
<!-- ===== Sidebar ===== -->
|
||
<aside class="sidebar" id="sidebar">
|
||
<div class="sidebar-logo">
|
||
<div class="logo-mark">📬</div>
|
||
<div>
|
||
<span>Outlook 邮件</span>
|
||
<small>v{{ APP_VERSION }}</small>
|
||
</div>
|
||
</div>
|
||
|
||
<nav class="sidebar-nav">
|
||
<div class="nav-section">概览</div>
|
||
<button class="nav-item active" data-page="dashboard" onclick="navigate('dashboard')">
|
||
<span class="nav-icon">🏠</span><span>仪表盘</span>
|
||
</button>
|
||
|
||
<div class="nav-section">邮箱管理</div>
|
||
<button class="nav-item" data-page="mailbox" onclick="navigate('mailbox')">
|
||
<span class="nav-icon">📬</span><span>账号管理</span>
|
||
</button>
|
||
<button class="nav-item" data-page="temp-emails" onclick="navigate('temp-emails')">
|
||
<span class="nav-icon">⚡</span><span>临时邮箱</span>
|
||
</button>
|
||
|
||
<div class="nav-section">Token</div>
|
||
<button class="nav-item" data-page="refresh-log" onclick="navigate('refresh-log')">
|
||
<span class="nav-icon">🔄</span><span>刷新日志</span>
|
||
</button>
|
||
|
||
<div class="nav-section">系统</div>
|
||
<button class="nav-item" data-page="settings" onclick="navigate('settings')">
|
||
<span class="nav-icon">⚙️</span><span>系统设置</span>
|
||
</button>
|
||
<button class="nav-item" data-page="audit" onclick="navigate('audit')">
|
||
<span class="nav-icon">📋</span><span>审计日志</span>
|
||
</button>
|
||
</nav>
|
||
|
||
<div class="sidebar-bottom">
|
||
<div class="user-chip">
|
||
<div class="user-avatar">管</div>
|
||
<div class="user-chip-info">
|
||
<div class="user-chip-name">管理员</div>
|
||
<div class="user-chip-role">Outlook 管理</div>
|
||
</div>
|
||
</div>
|
||
<button class="btn-theme" id="themeToggleBtn" onclick="toggleTheme()">☀ 浅色模式</button>
|
||
<button class="btn-logout" onclick="logout()">退出登录</button>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- Mobile sidebar backdrop -->
|
||
<div class="sidebar-backdrop" id="sidebarBackdrop" onclick="closeSidebar()"></div>
|
||
|
||
<!-- ===== Content ===== -->
|
||
<div class="content">
|
||
<!-- Topbar -->
|
||
<header class="topbar" id="topbar">
|
||
<div class="topbar-left">
|
||
<button class="hamburger-btn" onclick="toggleSidebar()">☰</button>
|
||
<div>
|
||
<div class="topbar-title" id="topbarTitle">仪表盘</div>
|
||
<div class="topbar-subtitle" id="topbarSubtitle">系统概览</div>
|
||
</div>
|
||
</div>
|
||
<div id="topbar-actions"></div>
|
||
</header>
|
||
|
||
<!-- Refresh progress bar (hidden by default) -->
|
||
<div class="refresh-progress-bar" id="refreshProgressBar" style="display:none;">
|
||
<span>🔄</span>
|
||
<span class="progress-text" id="refreshProgressText">正在刷新 Token…</span>
|
||
<div class="progress-track">
|
||
<div class="progress-fill" id="refreshProgressFill" style="width:0%"></div>
|
||
</div>
|
||
<span class="progress-text" id="refreshProgressCount">0 / 0</span>
|
||
<button class="btn btn-sm btn-ghost" onclick="stopRefresh()">停止</button>
|
||
</div>
|
||
|
||
<!-- ===== Page: Dashboard ===== -->
|
||
<div class="page" id="page-dashboard">
|
||
<div class="stat-grid" id="dashboardStats">
|
||
<div class="stat-card">
|
||
<div class="stat-label">总账号数</div>
|
||
<div class="stat-value" id="statTotalAccounts">-</div>
|
||
</div>
|
||
<div class="stat-card stat-success">
|
||
<div class="stat-label">Token 有效</div>
|
||
<div class="stat-value" id="statValidTokens">-</div>
|
||
</div>
|
||
<div class="stat-card stat-danger">
|
||
<div class="stat-label">Token 过期</div>
|
||
<div class="stat-value" id="statExpiredTokens">-</div>
|
||
</div>
|
||
<div class="stat-card stat-accent">
|
||
<div class="stat-label">临时邮箱</div>
|
||
<div class="stat-value" id="statTempEmails">-</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dashboard-grid">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-title">📂 分组概览</div>
|
||
</div>
|
||
<div class="card-body" style="padding:0;">
|
||
<ul class="dashboard-list" id="dashboardGroupList">
|
||
<li><span class="loading-overlay"><span class="spinner"></span> 加载中…</span></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-title">🔄 最近刷新</div>
|
||
</div>
|
||
<div class="card-body" style="padding:0;">
|
||
<ul class="dashboard-list" id="dashboardRefreshList">
|
||
<li><span class="loading-overlay"><span class="spinner"></span> 加载中…</span></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ===== Page: Mailbox (3-column) ===== -->
|
||
<div class="page page-hidden page-no-padding" id="page-mailbox">
|
||
<div class="mailbox-layout">
|
||
<!-- Groups Column -->
|
||
<div class="groups-column" id="groupPanel">
|
||
<div class="column-header">
|
||
<span class="column-title">分组</span>
|
||
<button class="btn-icon" onclick="showAddGroupModal()" title="添加分组">+</button>
|
||
</div>
|
||
<div class="column-search">
|
||
<input type="text" id="groupSearchInput" placeholder="搜索分组…" oninput="filterGroups(this.value)">
|
||
</div>
|
||
<div class="column-body" id="groupList">
|
||
<div class="loading-overlay"><span class="spinner"></span> 加载中…</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Resize Handle 1 -->
|
||
<div class="resize-handle" id="resizeHandle1" data-left="groupPanel" data-right="accountPanel"></div>
|
||
|
||
<!-- Accounts Column -->
|
||
<div class="accounts-column" id="accountPanel">
|
||
<div class="column-header">
|
||
<span class="column-title">
|
||
<span class="group-color-dot" id="currentGroupColor" style="background-color:#666;"></span>
|
||
<span id="currentGroupName">选择分组</span>
|
||
</span>
|
||
<div style="display:flex;gap:4px;">
|
||
<button class="btn-icon" onclick="showTagManagementModal()" title="管理标签">🏷️</button>
|
||
<button class="btn-icon" onclick="showAddAccountModal()" title="导入账号">+</button>
|
||
</div>
|
||
</div>
|
||
<div class="column-search">
|
||
<input type="text" id="globalSearch" placeholder="搜索邮箱地址…" autocomplete="off">
|
||
</div>
|
||
<div style="padding:6px 12px;border-bottom:1px solid var(--border-light);display:flex;align-items:center;gap:8px;font-size:0.78rem;flex-shrink:0;">
|
||
<label style="color:var(--text-muted);font-weight:500;">排序:</label>
|
||
<button class="btn btn-sm sort-btn active" data-sort="refresh_time" onclick="sortAccounts('refresh_time')">🕐 刷新时间</button>
|
||
<button class="btn btn-sm sort-btn" data-sort="email" onclick="sortAccounts('email')">📧 邮箱名</button>
|
||
<div style="margin-left:auto;display:flex;align-items:center;gap:4px;">
|
||
<input type="checkbox" id="selectAllCheckbox" onclick="toggleSelectAll()" style="cursor:pointer;">
|
||
<label for="selectAllCheckbox" style="font-size:0.72rem;color:var(--text-muted);cursor:pointer;">全选</label>
|
||
</div>
|
||
</div>
|
||
<div id="tagFilterContainer" style="padding:6px 12px;border-bottom:1px solid var(--border-light);display:none;flex-wrap:wrap;gap:6px;"></div>
|
||
<div class="column-body" id="accountList">
|
||
<div class="empty-state">
|
||
<span class="empty-icon">📁</span>
|
||
<p>请从左侧选择一个分组</p>
|
||
</div>
|
||
</div>
|
||
<div id="batchActionBar" class="batch-action-bar" style="display:none;">
|
||
<span id="selectedCount" style="font-size:0.78rem;color:var(--text-muted);">已选 0 项</span>
|
||
<div style="flex:1;"></div>
|
||
<button class="btn btn-sm btn-ghost" onclick="showBatchTagModal('add')">打标签</button>
|
||
<button class="btn btn-sm btn-ghost" onclick="showBatchTagModal('remove')">去标签</button>
|
||
<button class="btn btn-sm btn-ghost" onclick="showBatchMoveGroupModal()">移动分组</button>
|
||
<button class="btn btn-sm btn-danger" onclick="showBatchDeleteConfirm()">删除</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Resize Handle 2 -->
|
||
<div class="resize-handle" id="resizeHandle2" data-left="accountPanel" data-right="emailListPanel"></div>
|
||
|
||
<!-- Emails Column -->
|
||
<div class="emails-column" id="emailListPanel">
|
||
<div class="column-header">
|
||
<div style="display:flex;align-items:center;gap:8px;">
|
||
<div class="email-tabs" id="folderTabs" style="display:none;border:none;">
|
||
<button class="email-tab active" data-folder="inbox" onclick="switchFolder('inbox')">📨 收件箱</button>
|
||
<button class="email-tab" data-folder="junkemail" onclick="switchFolder('junkemail')">⚠️ 垃圾邮件</button>
|
||
</div>
|
||
<span style="font-size:0.82rem;color:var(--text-muted);" id="emailCount"></span>
|
||
<span id="methodTag" style="display:none;" class="badge badge-gray"></span>
|
||
</div>
|
||
<div style="display:flex;gap:4px;">
|
||
<button class="btn btn-sm btn-primary" onclick="refreshEmails()">获取邮件</button>
|
||
</div>
|
||
</div>
|
||
<!-- Current account info bar -->
|
||
<div id="currentAccountBar" style="display:none;padding:0.5rem 1rem;background:var(--bg-card);border-bottom:1px solid var(--border-light);font-size:0.82rem;">
|
||
<span id="currentAccount" onclick="copyCurrentEmail()" title="点击复制邮箱地址" style="cursor:pointer;">
|
||
当前邮箱:<strong id="currentAccountEmail"></strong>
|
||
</span>
|
||
</div>
|
||
<div class="column-body" id="emailList">
|
||
<div class="empty-state">
|
||
<span class="empty-icon">📬</span>
|
||
<p>请从左侧选择一个邮箱账号</p>
|
||
</div>
|
||
</div>
|
||
<div id="emailBatchActionBar" class="batch-action-bar" style="display:none;">
|
||
<span id="emailSelectedCount" style="font-size:0.78rem;color:var(--text-muted);">已选 0 项</span>
|
||
<div style="flex:1;"></div>
|
||
<button class="btn btn-sm btn-danger" onclick="confirmBatchDeleteEmails()">🗑️ 删除</button>
|
||
</div>
|
||
<!-- Email Detail (inline below email list) -->
|
||
<div id="emailDetailSection" style="display:none;border-top:1px solid var(--border);">
|
||
<div class="email-detail-toolbar" id="emailDetailToolbar">
|
||
<button class="btn btn-sm btn-ghost" onclick="showEmailList()">← 返回</button>
|
||
<button class="btn btn-sm btn-ghost" onclick="openFullscreenEmail()">🔍 全屏查看</button>
|
||
<button class="btn btn-sm btn-accent" onclick="extractVerificationFromDetail(this)" title="从邮件正文提取验证码/链接" style="font-size:0.72rem;padding:2px 8px;">🔑 验证码</button>
|
||
<label style="display:flex;align-items:center;gap:4px;font-size:0.78rem;margin-left:8px;cursor:pointer;">
|
||
<input type="checkbox" id="trustEmailCheckbox" onchange="toggleTrustMode(this)">
|
||
<span style="user-select:none;">信任此邮件</span>
|
||
</label>
|
||
<div style="flex:1;"></div>
|
||
<button class="btn btn-sm btn-danger" onclick="confirmDeleteCurrentEmail()">🗑️ 删除</button>
|
||
</div>
|
||
<div class="email-detail-container" id="emailDetail">
|
||
<div class="empty-state">
|
||
<span class="empty-icon">📄</span>
|
||
<p>选择一封邮件查看详情</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ===== Page: Temp Emails ===== -->
|
||
<div class="page page-hidden page-no-padding" id="page-temp-emails">
|
||
<div class="mailbox-layout">
|
||
<!-- Temp Email List Column -->
|
||
<div class="accounts-column" id="tempEmailPanel" style="width:300px;">
|
||
<div class="column-header">
|
||
<span class="column-title">⚡ 临时邮箱</span>
|
||
<button class="btn btn-sm btn-primary" onclick="generateTempEmail()">+ 创建</button>
|
||
</div>
|
||
<div class="column-body" id="tempEmailContainer">
|
||
<div class="empty-state">
|
||
<span class="empty-icon">📭</span>
|
||
<p>暂无临时邮箱</p>
|
||
<button class="btn btn-primary" onclick="generateTempEmail()">创建第一个临时邮箱</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- Temp Email Messages Column -->
|
||
<div class="emails-column">
|
||
<div class="column-header">
|
||
<span class="column-title" id="tempEmailCurrentName">选择一个临时邮箱</span>
|
||
<div style="display:flex;gap:4px;">
|
||
<button class="btn btn-sm btn-ghost" id="tempEmailRefreshBtn" onclick="if(currentAccount && isTempEmailGroup) loadTempEmailMessages(currentAccount)" style="display:none;">🔄 获取邮件</button>
|
||
</div>
|
||
</div>
|
||
<div class="column-body" id="tempEmailMessageList">
|
||
<div class="empty-state">
|
||
<span class="empty-icon">📬</span>
|
||
<p>选择一个临时邮箱查看邮件</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ===== Page: Refresh Log ===== -->
|
||
<div class="page page-hidden" id="page-refresh-log">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-title">🔄 刷新日志</div>
|
||
</div>
|
||
<div class="card-body" id="refreshLogContainer">
|
||
<div class="loading-overlay"><span class="spinner"></span> 加载中…</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ===== Page: Settings ===== -->
|
||
<div class="page page-hidden" id="page-settings" style="padding: 1.5rem; max-width: 720px;">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-title">⚙️ 系统设置</div>
|
||
</div>
|
||
<div class="card-body" style="padding: 1.5rem;">
|
||
<!-- 基础设置 -->
|
||
<div class="form-group">
|
||
<label class="form-label">登录密码</label>
|
||
<input type="password" class="form-input" id="settingsPassword" placeholder="输入新密码(留空则不修改)">
|
||
<div class="form-hint">用于登录系统的密码</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">GPTMail API Key</label>
|
||
<input type="text" class="form-input" id="settingsApiKey" placeholder="输入 GPTMail API Key">
|
||
<div class="form-hint">用于临时邮箱功能,可从 <a href="https://mail.chatgpt.org.uk/api" target="_blank" style="color: var(--clr-primary);">gptmail.io</a> 获取</div>
|
||
</div>
|
||
|
||
<!-- Token 刷新设置 -->
|
||
<div style="border-top: 1px solid var(--border-light); margin: 1.5rem 0; padding-top: 1.5rem;">
|
||
<h4 style="font-size: 0.95rem; font-weight: 600; margin-bottom: 1rem; color: var(--text);">🔄 Token 刷新设置</h4>
|
||
<div class="form-group">
|
||
<label style="display: flex; align-items: center; gap: 8px; cursor: pointer;">
|
||
<input type="checkbox" id="enableScheduledRefresh" checked>
|
||
<span class="form-label" style="margin: 0;">启用定时刷新</span>
|
||
</label>
|
||
<div class="form-hint">关闭后将不会自动执行定时刷新任务</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">刷新策略</label>
|
||
<div style="display: flex; gap: 16px; margin-bottom: 12px;">
|
||
<label style="display: flex; align-items: center; gap: 6px; cursor: pointer;">
|
||
<input type="radio" name="refreshStrategy" value="days" checked onchange="toggleRefreshStrategy()">
|
||
<span>按天数</span>
|
||
</label>
|
||
<label style="display: flex; align-items: center; gap: 6px; cursor: pointer;">
|
||
<input type="radio" name="refreshStrategy" value="cron" onchange="toggleRefreshStrategy()">
|
||
<span>Cron 表达式</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<div id="daysStrategyContainer">
|
||
<div class="form-group">
|
||
<label class="form-label">定时刷新周期 <span style="font-size: 0.75rem; color: var(--text-muted); font-weight: 400;">(每隔 X 天自动刷新所有账号)</span></label>
|
||
<div style="display: flex; align-items: center; gap: 8px;">
|
||
<input type="number" class="form-input" id="refreshIntervalDays" min="1" max="90" value="30" placeholder="30" style="max-width: 120px;">
|
||
<span style="font-size: 0.88rem; color: var(--text-muted); font-weight: 500;">天</span>
|
||
</div>
|
||
<div class="form-hint">建议设置为 30 天,防止 Token 因 90 天不使用而过期</div>
|
||
</div>
|
||
</div>
|
||
<div id="cronStrategyContainer" style="display: none;">
|
||
<div class="form-group">
|
||
<label class="form-label">Cron 表达式</label>
|
||
<input type="text" class="form-input" id="refreshCron" placeholder="0 2 * * *" value="0 2 * * *">
|
||
<div class="form-hint">格式:分 时 日 月 星期(例如:0 2 * * * 表示每天凌晨 2:00)</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">常用样例</label>
|
||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 8px;">
|
||
<button class="btn btn-sm btn-secondary" onclick="selectCronExample('0 2 * * *')">每天凌晨 2:00</button>
|
||
<button class="btn btn-sm btn-secondary" onclick="selectCronExample('0 2 * * 1')">每周一凌晨 2:00</button>
|
||
<button class="btn btn-sm btn-secondary" onclick="selectCronExample('0 2 1 * *')">每月 1 号凌晨 2:00</button>
|
||
<button class="btn btn-sm btn-secondary" onclick="selectCronExample('0 2 */3 * *')">每 3 天凌晨 2:00</button>
|
||
<button class="btn btn-sm btn-secondary" onclick="selectCronExample('0 */12 * * *')">每 12 小时</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<button class="btn btn-secondary" onclick="validateCronExpression()">验证表达式</button>
|
||
<div id="cronValidationResult" style="margin-top: 8px; font-size: 0.82rem;"></div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">邮箱间刷新间隔 <span style="font-size: 0.75rem; color: var(--text-muted); font-weight: 400;">(每个邮箱刷新之间的等待时间)</span></label>
|
||
<div style="display: flex; align-items: center; gap: 8px;">
|
||
<input type="number" class="form-input" id="refreshDelaySeconds" min="0" max="60" value="5" placeholder="5" style="max-width: 120px;">
|
||
<span style="font-size: 0.88rem; color: var(--text-muted); font-weight: 500;">秒</span>
|
||
</div>
|
||
<div class="form-hint">建议设置为 5-10 秒,避免频繁请求触发 API 限流</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 自动轮询设置 -->
|
||
<div style="border-top: 1px solid var(--border-light); margin: 1.5rem 0; padding-top: 1.5rem;">
|
||
<h4 style="font-size: 0.95rem; font-weight: 600; margin-bottom: 1rem; color: var(--text);">🔔 自动轮询设置</h4>
|
||
<div class="form-group">
|
||
<label style="display: flex; align-items: center; gap: 8px; cursor: pointer;">
|
||
<input type="checkbox" id="enableAutoPolling">
|
||
<span class="form-label" style="margin: 0;">启用自动轮询</span>
|
||
</label>
|
||
<div class="form-hint">开启后自动检查当前账号是否有新邮件</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">轮询间隔 <span style="font-size: 0.75rem; color: var(--text-muted); font-weight: 400;">(检查新邮件的时间间隔)</span></label>
|
||
<div style="display: flex; align-items: center; gap: 8px;">
|
||
<input type="number" class="form-input" id="pollingInterval" min="5" max="300" value="10" placeholder="10" style="max-width: 120px;">
|
||
<span style="font-size: 0.88rem; color: var(--text-muted); font-weight: 500;">秒</span>
|
||
</div>
|
||
<div class="form-hint">范围:5-300 秒,建议设置为 10-30 秒</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">轮询次数 <span style="font-size: 0.75rem; color: var(--text-muted); font-weight: 400;">(最多轮询多少次后停止)</span></label>
|
||
<div style="display: flex; align-items: center; gap: 8px;">
|
||
<input type="number" class="form-input" id="pollingCount" min="1" max="100" value="5" placeholder="5" style="max-width: 120px;">
|
||
<span style="font-size: 0.88rem; color: var(--text-muted); font-weight: 500;">次</span>
|
||
</div>
|
||
<div class="form-hint">范围:1-100 次,设置为 0 表示持续轮询</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 保存按钮 -->
|
||
<div style="display: flex; justify-content: flex-end; gap: 0.6rem; margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid var(--border-light);">
|
||
<button class="btn btn-primary" onclick="saveSettings()">💾 保存设置</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ===== Page: Audit ===== -->
|
||
<div class="page page-hidden" id="page-audit">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-title">📋 审计日志</div>
|
||
</div>
|
||
<div class="card-body" id="auditLogContainer">
|
||
<div class="loading-overlay"><span class="spinner"></span> 加载中…</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Toast container -->
|
||
<div id="toast-container" aria-live="polite"></div>
|
||
|
||
{% include 'partials/modals.html' %}
|
||
|
||
{% include 'partials/scripts.html' %}
|
||
</body>
|
||
|
||
</html>
|