f103148ebf
基于 Flask + MySQL + Bootstrap 5 的全栈个人资料库管理系统。 主要功能: - 管理员/普通用户双角色权限体系,全站登录保护 - 资源管理:文本、图片、音频、视频四类资源 - 三种添加方式:本地上传(拖拽)、URL 后台下载、磁力下载(aria2c) - 在线预览:文本、图片、HTML5 音视频播放器 - 安全:bcrypt 加盐密码哈希、CSRF 防护、SQLAlchemy ORM 防注入 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
88 lines
3.1 KiB
HTML
88 lines
3.1 KiB
HTML
{% extends 'base.html' %}
|
|
{% block title %}{{ title }}{% endblock %}
|
|
|
|
{% block breadcrumb %}
|
|
<ol class="breadcrumb mb-0">
|
|
<li class="breadcrumb-item"><a href="{{ url_for('admin.dashboard') }}">控制台</a></li>
|
|
<li class="breadcrumb-item"><a href="{{ url_for('admin.users') }}">用户管理</a></li>
|
|
<li class="breadcrumb-item active">{{ title }}</li>
|
|
</ol>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="row justify-content-center">
|
|
<div class="col-md-7 col-lg-6">
|
|
<div class="card shadow-sm">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="bi bi-person-{{ 'plus' if action == 'create' else 'gear' }} me-2"></i>
|
|
{{ title }}
|
|
</h5>
|
|
</div>
|
|
<div class="card-body p-4">
|
|
<form method="POST" novalidate>
|
|
{{ form.hidden_tag() }}
|
|
|
|
{% macro render_field(f, ph='') %}
|
|
<div class="mb-3">
|
|
<label class="form-label fw-medium">{{ f.label.text }}</label>
|
|
{{ f(class='form-control' + (' is-invalid' if f.errors else ''),
|
|
placeholder=ph) }}
|
|
{% for err in f.errors %}
|
|
<div class="invalid-feedback">{{ err }}</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endmacro %}
|
|
|
|
{{ render_field(form.username, '用户名') }}
|
|
{{ render_field(form.email, 'email@example.com') }}
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label fw-medium">{{ form.password.label.text }}</label>
|
|
<div class="input-group">
|
|
{{ form.password(class='form-control' + (' is-invalid' if form.password.errors else ''),
|
|
placeholder='至少 8 位', id='adminPwd') }}
|
|
<button class="btn btn-outline-secondary" type="button"
|
|
onclick="togglePwd('adminPwd',this)">
|
|
<i class="bi bi-eye"></i>
|
|
</button>
|
|
</div>
|
|
{% for err in form.password.errors %}
|
|
<div class="text-danger small">{{ err }}</div>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label fw-medium">{{ form.role.label.text }}</label>
|
|
{{ form.role(class='form-select') }}
|
|
</div>
|
|
|
|
<div class="mb-4 form-check">
|
|
{{ form.is_active(class='form-check-input') }}
|
|
<label class="form-check-label">{{ form.is_active.label.text }}</label>
|
|
</div>
|
|
|
|
<div class="d-flex gap-2">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="bi bi-check-lg me-1"></i>{{ '创建' if action == 'create' else '保存' }}
|
|
</button>
|
|
<a href="{{ url_for('admin.users') }}" class="btn btn-secondary">取消</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
function togglePwd(id, btn) {
|
|
const input = document.getElementById(id);
|
|
const icon = btn.querySelector('i');
|
|
input.type = input.type === 'password' ? 'text' : 'password';
|
|
icon.className = input.type === 'text' ? 'bi bi-eye-slash' : 'bi bi-eye';
|
|
}
|
|
</script>
|
|
{% endblock %}
|