文件
workbuddy-portal/workbuddy_portal/web/templates/base.html
T
wangchuanli 1bf961f6b3 feat(权限): 收敛普通账号写权限至本人凭证
将调度时刻、采集参数等实例级配置收归管理员,普通账号仅可维护本人 Cookie 与 User-Agent。
新增 config.writable_by 作为唯一写权限入口,set_setting 强制全局键落到 user_id=0,
消除「管理员改了只有自己生效」的静默缺陷。新增 tools/check_docs.py 文档自检,
smoke 断言扩至 215 项、check_live 扩至 122 项并支持普通账号越权验收,
忽略 backups/、data/*.bak* 与 legacy-v1/,版本升至 v1.3.0。
2026-09-18 08:46:00 +08:00

78 行
3.3 KiB
HTML
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="dark">
<meta name="robots" content="noindex, nofollow">
<title>{% block title %}{{ project_title }}{% endblock %}</title>
<link rel="icon" href="{{ url_for('static', filename='favicon.svg') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/app.css') }}">
</head>
<body>
{% set nav = active|default('') %}
{% set on_dash = request.path.startswith('/dashboard') %}
{# 变量名刻意叫 cur 而不是 me:模板里的 {% set %} 会覆盖子模板传入的同名变量,
而 current_user() 只含 id/username/display_name/is_admin —— 曾因此让
个人中心把 me.created_at 渲染成空(子模板的 me 是完整的用户行)。 #}
{% set cur = current_user() %}
{% if cur %}
<header class="topbar">
<div class="brand">
<span class="dot"></span>
<a href="{{ url_for('views.overview') }}"><b>{{ project_title }}</b></a>
<span class="ver">v{{ app_version }}</span>
</div>
<nav>
<a href="{{ url_for('views.overview') }}" class="{{ 'on' if nav=='overview' }}">概览</a>
<a href="{{ url_for('views.dashboard') }}" class="{{ 'on' if on_dash }}">用量大屏</a>
<a href="{{ url_for('views.records') }}" class="{{ 'on' if nav=='records' }}">数据明细</a>
<a href="{{ url_for('views.tasks') }}" class="{{ 'on' if nav=='tasks' }}">任务管理</a>
<a href="{{ url_for('views.config_page') }}" class="{{ 'on' if nav=='config' }}">配置管理</a>
{# 日志管理里是实例运行信息(数据库路径 / 账号名 / 来源 IP),仅管理员可见;
服务端另有 @admin_required 兜底,这里隐藏只是不给出会 403 的死链。 #}
{% if cur.is_admin %}
<a href="{{ url_for('views.logs') }}" class="{{ 'on' if nav=='logs' }}">日志管理</a>
{% endif %}
{% if cur.is_admin %}
<a href="{{ url_for('views.users_page') }}" class="{{ 'on' if nav=='users' }}">用户管理</a>
{% endif %}
</nav>
<div class="me">
<a class="who" href="{{ url_for('views.profile_page') }}" title="个人中心">
<b>{{ cur.display_name }}</b>
{% if cur.is_admin %}<span class="tag accent">管理员</span>
{% else %}<span class="tag mute">普通账号</span>{% endif %}
</a>
{# 退出用 POST + CSRF:GET 型退出会被 <img src="/logout"> 这类请求静默触发 #}
<form method="post" action="{{ url_for('views.logout_post') }}" style="margin:0">
<input type="hidden" name="_csrf" value="{{ csrf_token() }}">
<button class="btn ghost sm" type="submit">退出</button>
</form>
</div>
</header>
{% endif %}
<main class="wrap">
{% with msgs = get_flashed_messages(with_categories=true) %}
{% if msgs %}
<div class="flashes">
{% for cat, m in msgs %}<div class="flash {{ cat }}">{{ m }}</div>{% endfor %}
</div>
{% endif %}
{% endwith %}
{% block body %}{% endblock %}
</main>
<footer class="foot">
<b>{{ project_title }}</b> · {{ project_name }} · 多用户 · 调度与采集参数由管理员统一设定<br>
每个账号只使用并只见得到<b>自己的</b> Cookie 与用量数据;数据正本 <code>data/usage.sqlite</code>
</footer>
<script>
window.WB_CSRF = "{{ csrf_token() }}";
</script>
{% block scripts %}{% endblock %}
</body>
</html>