fix(admin-invites): unify form field styles, fix mobile layout for create and edit forms

This commit is contained in:
2026-07-06 08:10:36 +08:00
parent b58956937e
commit b66527b6d8
2 changed files with 53 additions and 34 deletions

View File

@@ -285,3 +285,18 @@ code { background: var(--bg); padding: .15rem .4rem; border-radius: 4px; font-si
.detail-title-row h1 { font-size: 1.2rem; }
.btn-back { padding: .25rem .5rem; font-size: .85rem; }
}
/* Admin invite form */
.admin-invite-form { display: flex; flex-wrap: wrap; gap: .5rem; align-items: flex-end; }
.aif-field { display: flex; flex-direction: column; gap: .15rem; }
.aif-grow { flex: 1 1 200px; min-width: 0; }
.aif-label { font-size: .75rem; color: var(--text-muted); }
.aif-input, .aif-select { padding: .4rem .6rem; border: 1px solid var(--border); border-radius: 6px; font-size: .85rem; background: #fff; }
.aif-input:focus, .aif-select:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(37,99,235,.1); }
.aif-short { width: 80px; }
.aif-date { width: 180px; }
.aif-btn-wrap { flex-direction: row; align-items: center; gap: .4rem; padding-bottom: 1px; }
.aif-btn { height: 2rem; }
.aif-edit-num, .aif-edit-date { flex-direction: row; align-items: center; gap: .35rem; }
.aif-edit-num .aif-input, .aif-edit-date .aif-input { width: 80px; flex: none; }
.aif-edit-num .aif-label, .aif-edit-date .aif-label { display: none; }

View File

@@ -15,28 +15,30 @@
<!-- Add new code -->
<div style="margin-bottom:2rem;padding:1.5rem;background:var(--card-bg);border-radius:var(--radius);border:1px solid var(--border)">
<h3 style="margin-bottom:1rem;font-size:1rem">创建邀请码</h3>
<form method="post" action="/admin/invites/add" style="display:flex;flex-wrap:wrap;gap:.75rem;align-items:end">
<div style="flex:1;min-width:200px">
<label style="display:block;font-size:.8rem;color:var(--text-muted);margin-bottom:.25rem">邀请码(留空自动生成)</label>
<input type="text" name="code" maxlength="8" placeholder="自动生成" style="text-transform:uppercase">
<form method="post" action="/admin/invites/add" class="admin-invite-form">
<div class="aif-field aif-grow">
<label class="aif-label">邀请码(留空自动生成)</label>
<input type="text" name="code" maxlength="8" placeholder="自动生成" class="aif-input" style="text-transform:uppercase">
</div>
<div style="min-width:140px">
<label style="display:block;font-size:.8rem;color:var(--text-muted);margin-bottom:.25rem">限制类型</label>
<select name="limit_type" id="limit_type" onchange="toggleLimitFields()">
<div class="aif-field">
<label class="aif-label">限制类型</label>
<select name="limit_type" id="limit_type" onchange="toggleLimitFields()" class="aif-select">
<option value="unlimited">无限制</option>
<option value="uses">使用次数</option>
<option value="expires">有效期</option>
</select>
</div>
<div id="max_uses_field" style="display:none;min-width:120px">
<label style="display:block;font-size:.8rem;color:var(--text-muted);margin-bottom:.25rem">最大使用次数</label>
<input type="number" name="max_uses" min="1" value="1">
<div class="aif-field" id="max_uses_field" style="display:none">
<label class="aif-label">最大次数</label>
<input type="number" name="max_uses" min="1" value="1" class="aif-input aif-short">
</div>
<div id="expires_field" style="display:none;min-width:180px">
<label style="display:block;font-size:.8rem;color:var(--text-muted);margin-bottom:.25rem">过期时间</label>
<input type="datetime-local" name="expires_at">
<div class="aif-field" id="expires_field" style="display:none">
<label class="aif-label">过期时间</label>
<input type="datetime-local" name="expires_at" class="aif-input aif-date">
</div>
<div class="aif-field aif-btn-wrap">
<button type="submit" class="btn btn-primary aif-btn">创建</button>
</div>
<button type="submit" class="btn btn-primary">创建</button>
</form>
</div>
@@ -44,13 +46,11 @@
{% if codes %}
<div class="postcard-list">
{% for c in codes %}
<div class="postcard-row">
<div style="flex:1;display:flex;align-items:center;gap:1rem;flex-wrap:wrap">
<div class="postcard-row" style="flex-direction:column;align-items:stretch;gap:.75rem">
<div style="display:flex;align-items:center;gap:1rem;flex-wrap:wrap">
<strong style="font-family:monospace;font-size:1.1rem">{{ c.code }}</strong>
<span style="font-size:.8rem;color:var(--text-muted)">创建者: {{ c.creator.username if c.creator else '-' }}</span>
<span style="font-size:.8rem;color:var(--text-muted)">{{ c.created_at.strftime('%Y-%m-%d %H:%M') }}</span>
</div>
<div style="display:flex;align-items:center;gap:.75rem;flex-wrap:wrap">
{% if c.max_uses is not none %}
<span class="badge">已用 {{ c.use_count }} / {{ c.max_uses }}</span>
{% else %}
@@ -61,20 +61,27 @@
{% else %}
<span class="badge">永不过期</span>
{% endif %}
<form method="post" action="/admin/invites/{{ c.id }}/edit" style="display:inline-flex;align-items:center;gap:.3rem;flex-wrap:wrap" id="edit-form-{{ c.id }}">
<select name="limit_type" style="width:auto;padding:2px 4px;font-size:.75rem" onchange="toggleEditFields({{ c.id }}, this.value)">
</div>
<form method="post" action="/admin/invites/{{ c.id }}/edit" class="admin-invite-form" id="edit-form-{{ c.id }}">
<div class="aif-field">
<select name="limit_type" class="aif-select" onchange="toggleEditFields({{ c.id }}, this.value)">
<option value="unlimited"{% if c.max_uses is none and not c.expires_at %} selected{% endif %}>无限制</option>
<option value="uses"{% if c.max_uses is not none %} selected{% endif %}>次数限制</option>
<option value="expires"{% if c.expires_at %} selected{% endif %}>有效期</option>
</select>
<input type="number" name="max_uses" value="{{ c.max_uses or 1 }}" min="1" style="width:60px;padding:2px 4px;font-size:.75rem;display:{% if c.max_uses is not none %}inline{% else %}none{% endif %}">
<input type="datetime-local" name="expires_at" value="{{ c.expires_at.strftime('%Y-%m-%dT%H:%M') if c.expires_at else '' }}" style="font-size:.75rem;display:{% if c.expires_at %}inline{% else %}none{% endif %}">
<button type="submit" class="btn btn-sm">保存</button>
</form>
<form method="post" action="/admin/invites/{{ c.id }}/delete" style="display:inline" onsubmit="return confirm('确定删除该邀请码?')">
<button type="submit" class="btn btn-danger btn-sm">删除</button>
</form>
</div>
<div class="aif-field aif-edit-num" style="display:{% if c.max_uses is not none %}flex{% else %}none{% endif %}">
<input type="number" name="max_uses" value="{{ c.max_uses or 1 }}" min="1" class="aif-input aif-short">
</div>
<div class="aif-field aif-edit-date" style="display:{% if c.expires_at %}flex{% else %}none{% endif %}">
<input type="datetime-local" name="expires_at" value="{{ c.expires_at.strftime('%Y-%m-%dT%H:%M') if c.expires_at else '' }}" class="aif-input aif-date">
</div>
<div class="aif-field aif-btn-wrap">
<button type="submit" class="btn btn-sm">保存</button>
<button type="button" class="btn btn-danger btn-sm" onclick="if(confirm('确定删除?'))this.closest('form').nextElementSibling.submit()">删除</button>
</div>
</form>
<form method="post" action="/admin/invites/{{ c.id }}/delete" style="display:none"></form>
</div>
{% endfor %}
</div>
@@ -88,16 +95,13 @@
<script>
function toggleLimitFields() {
var t = document.getElementById('limit_type').value;
document.getElementById('max_uses_field').style.display = t === 'uses' ? '' : 'none';
document.getElementById('expires_field').style.display = t === 'expires' ? '' : 'none';
document.getElementById('max_uses_field').style.display = t === 'uses' ? 'flex' : 'none';
document.getElementById('expires_field').style.display = t === 'expires' ? 'flex' : 'none';
}
function toggleEditFields(id, val) {
var form = document.getElementById('edit-form-' + id);
var inputs = form.querySelectorAll('input[name="max_uses"], input[name="expires_at"]');
inputs.forEach(function(inp) {
if (inp.name === 'max_uses') inp.style.display = val === 'uses' ? 'inline' : 'none';
if (inp.name === 'expires_at') inp.style.display = val === 'expires' ? 'inline' : 'none';
});
form.querySelector('.aif-edit-num').style.display = val === 'uses' ? 'flex' : 'none';
form.querySelector('.aif-edit-date').style.display = val === 'expires' ? 'flex' : 'none';
}
</script>
{% endblock %}