feat: 实现 Admin 采购员账号管理 (#51)

This commit is contained in:
chengma
2026-08-09 13:50:55 +08:00
parent 771e2ee616
commit eea0d65ef8
12 changed files with 909 additions and 20 deletions
+3
View File
@@ -15,6 +15,9 @@
<a href="/syb" class="{{if eq .Active "syb"}}active{{end}}">顺运宝数据</a>
<a href="/tasks" class="{{if eq .Active "tasks"}}active{{end}}">采集采购</a>
<a href="/clients" class="{{if eq .Active "clients"}}active{{end}}">客户端列表</a>
{{if and .CurrentUser .CurrentUser.IsAdmin}}
<a href="/users" class="{{if eq .Active "users"}}active{{end}}">用户管理</a>
{{end}}
{{if .CurrentUser}}
<span class="nav-user">{{.CurrentUser.Username}}</span>
<form class="nav-logout" method="post" action="/logout">
+140
View File
@@ -0,0 +1,140 @@
{{define "user/list"}}
{{template "header" .}}
<div class="toolbar">
<form class="inline grow" method="get" action="/users">
<label for="user-q">用户名</label>
<input id="user-q" class="search-narrow" type="text" name="q"
value="{{.Keyword}}" placeholder="搜索用户名">
<label for="user-status">状态</label>
<select id="user-status" name="status">
<option value="">全部</option>
<option value="active" {{if eq .StatusFilter "active"}}selected{{end}}>启用</option>
<option value="disabled" {{if eq .StatusFilter "disabled"}}selected{{end}}>禁用</option>
</select>
<button type="submit">搜索</button>
</form>
<button type="button" class="primary" data-modal-open="create-user-modal">新增采购员</button>
</div>
{{if .Message}}<p class="notice" role="status">{{.Message}}</p>{{end}}
{{if .Error}}<p class="missing" role="alert">{{.Error}}</p>{{end}}
<div class="table-wrap">
<table>
<thead>
<tr>
<th>用户名</th>
<th>角色</th>
<th>状态</th>
<th>最后登录</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{{range .Rows}}
<tr>
<td>{{.Username}}</td>
<td>{{.RoleLabel}}</td>
<td><span class="status-pill {{if .IsActive}}status-active{{else}}status-disabled{{end}}">{{.StatusLabel}}</span></td>
<td>{{if .LastLoginAt}}{{.LastLoginAt}}{{else}}从未登录{{end}}</td>
<td>{{.CreatedAt}}</td>
<td>
<div class="row-actions">
{{if .IsAdmin}}
<button type="button" disabled title="不能禁用最后一个有效管理员">唯一管理员</button>
{{else}}
<form method="post" action="/users/status"
data-confirm-submit="确定{{if .IsActive}}禁用{{else}}启用{{end}}采购员“{{.Username}}”吗?{{if .IsActive}}该账号的现有登录会立即失效。{{end}}">
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
<input type="hidden" name="user_id" value="{{.UserID}}">
<input type="hidden" name="status" value="{{if .IsActive}}disabled{{else}}active{{end}}">
<button type="submit" {{if .IsActive}}class="danger"{{end}}>{{if .IsActive}}禁用{{else}}启用{{end}}</button>
</form>
<button type="button" data-modal-open="reset-password-modal"
data-reset-user-id="{{.UserID}}" data-reset-username="{{.Username}}">重置密码</button>
{{end}}
</div>
</td>
</tr>
{{else}}
<tr class="empty">
<td colspan="6">
{{if .Keyword}}没有匹配的用户。<a href="/users">清除搜索条件</a>
{{else}}还没有用户。{{end}}
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
<div class="modal-backdrop" id="create-user-modal" {{if not .NeedCreate}}hidden{{end}}>
<div class="modal modal-narrow" role="dialog" aria-modal="true" aria-labelledby="create-user-title">
<div class="modal-head">
<h2 id="create-user-title">新增采购员</h2>
<button type="button" class="modal-x" data-modal-close aria-label="关闭">×</button>
</div>
<form method="post" action="/users/create">
<div class="modal-body form-stack">
<p class="hint">新账号固定为采购员,可使用业务页面,但不能进入用户管理。</p>
<div class="field">
<label for="new-username">用户名</label>
<input id="new-username" type="text" name="username" value="{{.CreateUsername}}" maxlength="64"
required autocomplete="off" autofocus>
</div>
<div class="field">
<label for="new-password">初始密码</label>
<input id="new-password" type="password" name="password" minlength="8"
maxlength="72" required autocomplete="new-password">
<small>至少 8 个字符。密码不会显示在列表或日志中。</small>
</div>
<div class="field">
<label for="new-password-confirm">确认密码</label>
<input id="new-password-confirm" type="password" name="password_confirm"
minlength="8" maxlength="72" required autocomplete="new-password">
</div>
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
</div>
<div class="modal-foot">
<button type="button" data-modal-close>取消</button>
<button type="submit" class="primary">创建采购员</button>
</div>
</form>
</div>
</div>
<div class="modal-backdrop" id="reset-password-modal" hidden>
<div class="modal modal-narrow" role="dialog" aria-modal="true" aria-labelledby="reset-password-title">
<div class="modal-head">
<h2 id="reset-password-title">重置采购员密码</h2>
<button type="button" class="modal-x" data-modal-close aria-label="关闭">×</button>
</div>
<form method="post" action="/users/reset-password"
data-confirm-submit="确定重置这个采购员的密码吗?现有登录会立即失效。">
<div class="modal-body form-stack">
<p>账号:<strong data-reset-username-label></strong></p>
<div class="field">
<label for="reset-password">新密码</label>
<input id="reset-password" type="password" name="password" minlength="8"
maxlength="72" required autocomplete="new-password" autofocus>
</div>
<div class="field">
<label for="reset-password-confirm">确认新密码</label>
<input id="reset-password-confirm" type="password" name="password_confirm"
minlength="8" maxlength="72" required autocomplete="new-password">
</div>
<input type="hidden" name="user_id" data-reset-user-id-input>
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
</div>
<div class="modal-foot">
<button type="button" data-modal-close>取消</button>
<button type="submit" class="danger">重置密码</button>
</div>
</form>
</div>
</div>
{{template "footer" .}}
{{end}}