update
This commit is contained in:
15
internal/handler/templates/pages/brand-form.html
Normal file
15
internal/handler/templates/pages/brand-form.html
Normal file
@ -0,0 +1,15 @@
|
||||
{{define "title"}}{{if .UID}}编辑品牌{{else}}新建品牌{{end}} · 管理后台{{end}}
|
||||
{{define "barLabel"}}管理后台 · {{if .UID}}编辑品牌{{else}}新建品牌{{end}}{{end}}
|
||||
{{define "barRight"}}<a href="/admin/brands">返回列表</a> · <a href="/admin/logout">退出</a>{{end}}
|
||||
{{define "content"}}
|
||||
{{template "bar" .}}
|
||||
<div class="main">
|
||||
<h1>{{if .UID}}编辑品牌{{else}}新建品牌{{end}}</h1>
|
||||
<form method="post" action="{{if .UID}}/admin/brands/{{.UID}}{{else}}/admin/brands{{end}}">
|
||||
{{if .Error}}<div class="err">{{.Error}}</div>{{end}}
|
||||
<label>英文名(name_en)</label><input name="name_en" value="{{.NameEn}}" placeholder="如 Acne Studios">
|
||||
<label>中文名(name_cn)</label><input name="name_cn" value="{{.NameCn}}" placeholder="如 艾克妮">
|
||||
<button type="submit">{{if .UID}}保存{{else}}创建{{end}}</button>
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
||||
51
internal/handler/templates/pages/brands.html
Normal file
51
internal/handler/templates/pages/brands.html
Normal file
@ -0,0 +1,51 @@
|
||||
{{define "title"}}品牌管理 · 管理后台{{end}}
|
||||
{{define "barLabel"}}管理后台 · 品牌管理{{end}}
|
||||
{{define "barRight"}}<a href="/admin/brands/new">+ 新建</a> · <a href="/admin/logout">退出</a>{{end}}
|
||||
{{define "content"}}
|
||||
{{template "bar" .}}
|
||||
<div class="main">
|
||||
<h1>品牌列表</h1>
|
||||
<form class="toolbar" method="get" action="/admin/brands">
|
||||
<input name="keyword" placeholder="搜索品牌名…" value="{{.Keyword}}">
|
||||
<button type="submit">搜索</button>
|
||||
{{if .Keyword}}<a href="/admin/brands">清除</a>{{end}}
|
||||
</form>
|
||||
<div class="idx">
|
||||
<a href="/admin/brands?keyword={{.Keyword}}" class="{{if eq .Letter ""}}on{{end}}">全部</a>
|
||||
<a href="/admin/brands?letter=OTHER&keyword={{.Keyword}}" class="{{if eq .Letter "OTHER"}}on{{end}}">中文</a>
|
||||
<a href="/admin/brands?letter=A&keyword={{.Keyword}}" class="{{if eq .Letter "A"}}on{{end}}">A</a>
|
||||
<a href="/admin/brands?letter=B&keyword={{.Keyword}}" class="{{if eq .Letter "B"}}on{{end}}">B</a>
|
||||
<a href="/admin/brands?letter=C&keyword={{.Keyword}}" class="{{if eq .Letter "C"}}on{{end}}">C</a>
|
||||
<a href="/admin/brands?letter=D&keyword={{.Keyword}}" class="{{if eq .Letter "D"}}on{{end}}">D</a>
|
||||
<a href="/admin/brands?letter=E&keyword={{.Keyword}}" class="{{if eq .Letter "E"}}on{{end}}">E</a>
|
||||
<a href="/admin/brands?letter=F&keyword={{.Keyword}}" class="{{if eq .Letter "F"}}on{{end}}">F</a>
|
||||
<a href="/admin/brands?letter=G&keyword={{.Keyword}}" class="{{if eq .Letter "G"}}on{{end}}">G</a>
|
||||
<a href="/admin/brands?letter=H&keyword={{.Keyword}}" class="{{if eq .Letter "H"}}on{{end}}">H</a>
|
||||
<a href="/admin/brands?letter=I&keyword={{.Keyword}}" class="{{if eq .Letter "I"}}on{{end}}">I</a>
|
||||
<a href="/admin/brands?letter=J&keyword={{.Keyword}}" class="{{if eq .Letter "J"}}on{{end}}">J</a>
|
||||
<a href="/admin/brands?letter=K&keyword={{.Keyword}}" class="{{if eq .Letter "K"}}on{{end}}">K</a>
|
||||
<a href="/admin/brands?letter=L&keyword={{.Keyword}}" class="{{if eq .Letter "L"}}on{{end}}">L</a>
|
||||
<a href="/admin/brands?letter=M&keyword={{.Keyword}}" class="{{if eq .Letter "M"}}on{{end}}">M</a>
|
||||
<a href="/admin/brands?letter=N&keyword={{.Keyword}}" class="{{if eq .Letter "N"}}on{{end}}">N</a>
|
||||
<a href="/admin/brands?letter=O&keyword={{.Keyword}}" class="{{if eq .Letter "O"}}on{{end}}">O</a>
|
||||
<a href="/admin/brands?letter=P&keyword={{.Keyword}}" class="{{if eq .Letter "P"}}on{{end}}">P</a>
|
||||
<a href="/admin/brands?letter=Q&keyword={{.Keyword}}" class="{{if eq .Letter "Q"}}on{{end}}">Q</a>
|
||||
<a href="/admin/brands?letter=R&keyword={{.Keyword}}" class="{{if eq .Letter "R"}}on{{end}}">R</a>
|
||||
<a href="/admin/brands?letter=S&keyword={{.Keyword}}" class="{{if eq .Letter "S"}}on{{end}}">S</a>
|
||||
<a href="/admin/brands?letter=T&keyword={{.Keyword}}" class="{{if eq .Letter "T"}}on{{end}}">T</a>
|
||||
<a href="/admin/brands?letter=U&keyword={{.Keyword}}" class="{{if eq .Letter "U"}}on{{end}}">U</a>
|
||||
<a href="/admin/brands?letter=V&keyword={{.Keyword}}" class="{{if eq .Letter "V"}}on{{end}}">V</a>
|
||||
<a href="/admin/brands?letter=W&keyword={{.Keyword}}" class="{{if eq .Letter "W"}}on{{end}}">W</a>
|
||||
<a href="/admin/brands?letter=X&keyword={{.Keyword}}" class="{{if eq .Letter "X"}}on{{end}}">X</a>
|
||||
<a href="/admin/brands?letter=Y&keyword={{.Keyword}}" class="{{if eq .Letter "Y"}}on{{end}}">Y</a>
|
||||
<a href="/admin/brands?letter=Z&keyword={{.Keyword}}" class="{{if eq .Letter "Z"}}on{{end}}">Z</a>
|
||||
</div>
|
||||
<table>
|
||||
<thead><tr><th>编码 ID</th><th>英文名</th><th>中文名</th></tr></thead>
|
||||
<tbody>
|
||||
{{range .Items}}<tr><td><code>{{.UID}}</code></td><td>{{.NameEn}}</td><td>{{.NameCn}}</td><td><a class="view" href="/admin/brands/{{.UID}}">编辑</a></td></tr>{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{template "pager" .Pager}}
|
||||
</div>
|
||||
{{end}}
|
||||
18
internal/handler/templates/pages/dashboard.html
Normal file
18
internal/handler/templates/pages/dashboard.html
Normal file
@ -0,0 +1,18 @@
|
||||
{{define "title"}}管理后台{{end}}
|
||||
{{define "barLabel"}}管理后台 · Fashion Archive{{end}}
|
||||
{{define "barRight"}}<a href="/admin/logout">退出({{.Username}})</a>{{end}}
|
||||
{{define "content"}}
|
||||
{{template "bar" .}}
|
||||
<div class="main">
|
||||
<h1>欢迎,{{.Username}}</h1>
|
||||
{{if .Kinds}}<div class="chips">{{range .Kinds}}{{if ne .Kind ""}}<span class="chip">{{.Label}}:待审 {{.Pending}}</span>{{end}}{{end}}</div>{{end}}
|
||||
<div class="cards">
|
||||
<a class="card" href="/admin/brands"><div class="t">品牌管理</div><div class="d">查看 / 搜索全部品牌</div></a>
|
||||
<a class="card" href="/admin/runways"><div class="t">走秀档案</div><div class="d">按系列 / 季节 / 年份筛选</div></a>
|
||||
<a class="card" href="/admin/street-snaps"><div class="t">街拍</div><div class="d">按城市 / 年份筛选</div></a>
|
||||
<a class="card" href="/admin/reviews"><div class="t">待审草稿{{if gt .PendingReviews 0}}({{.PendingReviews}}){{end}}</div><div class="d">爬虫入库待人工审核</div></a>
|
||||
<a class="card" href="/admin/ingest-jobs"><div class="t">入库任务</div><div class="d">爬虫上报处理进度 / 失败重试</div></a>
|
||||
<a class="card" href="/admin/users"><div class="t">用户管理</div><div class="d">账号等级 · 提级 VIP</div></a>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
5
internal/handler/templates/pages/error.html
Normal file
5
internal/handler/templates/pages/error.html
Normal file
@ -0,0 +1,5 @@
|
||||
{{define "title"}}错误{{end}}
|
||||
{{define "content"}}
|
||||
<h1>出错了</h1><p style="color:#c0392b">{{.Error}}</p>
|
||||
<p><a href="/admin/">返回首页</a></p>
|
||||
{{end}}
|
||||
24
internal/handler/templates/pages/ingest-jobs.html
Normal file
24
internal/handler/templates/pages/ingest-jobs.html
Normal file
@ -0,0 +1,24 @@
|
||||
{{define "title"}}入库任务 · 管理后台{{end}}
|
||||
{{define "barLabel"}}管理后台 · 爬虫入库任务{{end}}
|
||||
{{define "barRight"}}<a href="/admin/logout">退出</a>{{end}}
|
||||
{{define "content"}}
|
||||
{{template "bar" .}}
|
||||
<div class="main">
|
||||
<h1>爬虫入库任务</h1>
|
||||
<p class="muted">worker 每 3 秒扫描一次 pending 任务并处理;failed 可一键重新入队。共 {{.Total}} 条,当前第 {{.Page}} / {{if eq .TotalPages 0}}1{{else}}{{.TotalPages}}{{end}} 页(每页 {{.PageSize}} 条)。</p>
|
||||
<table>
|
||||
<thead><tr><th>ID</th><th>状态</th><th>重试</th><th>错误信息</th><th>更新时间</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
{{range .Jobs}}<tr>
|
||||
<td><code>{{.ID}}</code></td>
|
||||
<td><span class="badge {{.Status}}">{{.Status}}</span></td>
|
||||
<td>{{.Attempts}}</td>
|
||||
<td class="err break">{{.LastError}}</td>
|
||||
<td class="muted">{{.UpdatedAt}}</td>
|
||||
<td>{{if eq .Status "failed"}}<form class="retry" method="post" action="/admin/ingest-jobs/{{.ID}}/retry"><button class="retry" type="submit">重试</button></form>{{else}}<span class="muted">—</span>{{end}}</td>
|
||||
</tr>{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{template "pager" .Pager}}
|
||||
</div>
|
||||
{{end}}
|
||||
10
internal/handler/templates/pages/login.html
Normal file
10
internal/handler/templates/pages/login.html
Normal file
@ -0,0 +1,10 @@
|
||||
{{define "title"}}管理后台 · 登录{{end}}
|
||||
{{define "content"}}
|
||||
<div class="wrap"><h1>管理后台登录</h1>
|
||||
<form method="post" action="/admin/login">
|
||||
{{if .Error}}<div class="err">{{.Error}}</div>{{end}}
|
||||
<label>账号</label><input name="account" value="{{.Account}}" autofocus>
|
||||
<label>密码</label><input name="password" type="password">
|
||||
<button type="submit">登录</button>
|
||||
</form></div>
|
||||
{{end}}
|
||||
56
internal/handler/templates/pages/review-detail.html
Normal file
56
internal/handler/templates/pages/review-detail.html
Normal file
@ -0,0 +1,56 @@
|
||||
{{define "title"}}草稿审核 · 管理后台{{end}}
|
||||
{{define "barLabel"}}管理后台 · 草稿审核 #{{.Draft.ID}}{{end}}
|
||||
{{define "barRight"}}<a href="{{reviewDetailURL .Draft.Kind .Draft.ID}}">返回列表</a> · <a href="/admin/logout">退出</a>{{end}}
|
||||
{{define "content"}}
|
||||
{{template "bar" .}}
|
||||
<div class="main mid">
|
||||
<p class="muted">类型 <b>{{.Draft.Kind}}</b>{{if .BrandName}} · 品牌 {{.BrandName}}{{end}} · 状态 <b>{{.Draft.Status}}</b></p>
|
||||
|
||||
{{/* 字段微调 + 通过:仍是普通表单提交(无 JS 也能用);键盘 a 会触发同一个表单 */}}
|
||||
<form method="post" action="/admin/reviews/{{.Draft.Kind}}/{{.Draft.ID}}/approve">
|
||||
{{range .Draft.Fields}}<div><label>{{.Label}}</label>{{if eq .Type "textarea"}}<textarea name="{{.Name}}">{{.Value}}</textarea>{{else}}<input name="{{.Name}}" value="{{.Value}}"{{if eq .Type "number"}} inputmode="numeric"{{end}}>{{end}}</div>{{end}}
|
||||
<button type="submit">通过并发布</button>
|
||||
</form>
|
||||
|
||||
{{if eq .Draft.Kind "street"}}
|
||||
<div class="hint">
|
||||
操作:勾选属于同一个人的图片 → 在<b>其中一张</b>上点「主图」→ 点底部「合并选中为一组」。副图上的「拆出」可恢复为独立主图。<br>
|
||||
快捷键:<b>j</b>/<b>k</b> 上下移动 · <b>x</b> 勾选 · <b>m</b> 设为主图 · <b>d</b> 拆出 · <b>Enter</b> 看大图 · <b>a</b> 通过
|
||||
<button type="button" class="x" id="hint-dismiss" aria-label="收起提示">✕</button>
|
||||
</div>
|
||||
|
||||
<h2>图片(<span id="img-stat">{{len .Draft.Images}} 张 · {{len .Draft.Groups}} 组</span>)</h2>
|
||||
{{/* 合并表单本体在 grid 之前;各格的 radio/checkbox 通过 form="batch" 关联过来 */}}
|
||||
<form id="batch" method="post" action="/admin/reviews/{{.Draft.Kind}}/{{.Draft.ID}}/images/attach"></form>
|
||||
<div class="grid">
|
||||
{{range .Draft.Images}}<div class="cell{{if eq .IsDetail 1}} det{{end}}" data-img-id="{{.ID}}">
|
||||
<button class="thumb" type="button" data-zoom><img src="{{.Image}}" loading="lazy"></button>
|
||||
<span class="role">{{if eq .IsDetail 1}}副图 → #{{.ParentImageID}}{{else}}主图{{if .DetailCount}} · {{.DetailCount}} 副图{{end}}{{end}}</span>
|
||||
<span class="nm">{{.Name}}</span>
|
||||
<div class="acts">
|
||||
{{if eq .IsDetail 0}}<label class="chk" data-only="main"><input type="radio" form="batch" name="main" value="{{.ID}}"> 主图</label>{{end}}
|
||||
<label class="chk"><input type="checkbox" form="batch" name="img" value="{{.ID}}"> 选入</label>
|
||||
{{if eq .IsDetail 1}}<form data-only="detail" method="post" action="/admin/reviews/{{$.Draft.Kind}}/{{$.Draft.ID}}/images/{{.ID}}/detach"><button type="submit">拆出</button></form>{{end}}
|
||||
<form method="post" action="/admin/reviews/{{$.Draft.Kind}}/{{$.Draft.ID}}/images/{{.ID}}/delete"><button type="submit" class="reject" onclick="return confirm('确认删除这张图片?')">删除</button></form>
|
||||
</div>
|
||||
</div>{{end}}
|
||||
</div>
|
||||
|
||||
<div class="batchbar">
|
||||
<button type="submit" form="batch">合并选中为一组</button>
|
||||
<span class="muted">勾选同一人的图,并在其中一张主图上点「主图」</span>
|
||||
</div>
|
||||
{{else}}
|
||||
<h2>图片管理({{len .Draft.Images}} 张)</h2>
|
||||
<div class="grid">
|
||||
{{range .Draft.Images}}<div class="cell" data-img-id="{{.ID}}">
|
||||
<button class="thumb" type="button" data-zoom><img src="{{.Image}}" loading="lazy"></button>
|
||||
<span class="nm">{{.Name}}</span>
|
||||
<div class="acts">
|
||||
<form method="post" action="/admin/reviews/{{$.Draft.Kind}}/{{$.Draft.ID}}/images/{{.ID}}/delete"><button type="submit" class="reject" onclick="return confirm('确认删除这张图片?')">删除</button></form>
|
||||
</div>
|
||||
</div>{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
50
internal/handler/templates/pages/review-list.html
Normal file
50
internal/handler/templates/pages/review-list.html
Normal file
@ -0,0 +1,50 @@
|
||||
{{define "title"}}待审草稿 · 管理后台{{end}}
|
||||
{{define "barLabel"}}待审草稿{{end}}
|
||||
{{define "barRight"}}<a href="/admin/logout">退出</a>{{end}}
|
||||
{{define "content"}}
|
||||
{{template "bar" .}}
|
||||
<div class="main">
|
||||
<h1>待审草稿(共 {{.Total}} 条)</h1>
|
||||
<div class="kinds">
|
||||
{{range .Kinds}}<a href="{{if eq .Kind ""}}/admin/reviews{{else}}/admin/reviews/{{.Kind}}{{end}}" class="{{if or (eq $.Kind .Kind) (eq $.Kind "all")}}on{{end}}">{{.Label}}{{if gt .Pending 0}}({{.Pending}}){{end}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="tabs">
|
||||
<a href="/admin/reviews{{.ListBase}}" class="{{if eq .Status ""}}on{{end}}">全部</a>
|
||||
<a href="/admin/reviews{{.ListBase}}?status=pending" class="{{if eq .Status "pending"}}on{{end}}">待审核</a>
|
||||
<a href="/admin/reviews{{.ListBase}}?status=approved" class="{{if eq .Status "approved"}}on{{end}}">已通过</a>
|
||||
<a href="/admin/reviews{{.ListBase}}?status=rejected" class="{{if eq .Status "rejected"}}on{{end}}">已驳回</a>
|
||||
</div>
|
||||
|
||||
{{/* 多选 + 批量操作:勾选后底部出现操作条(admin.js 接管;无 JS 时单条「查看/审核」照常可用) */}}
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr>
|
||||
<th style="width:30px"><input type="checkbox" id="sel-all" aria-label="全选本页"></th>
|
||||
<th>ID</th><th>类型</th><th>标题</th><th>副标题</th><th>图数</th><th>状态</th><th>操作</th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
{{range .Drafts}}<tr data-kind="{{.Kind}}" data-id="{{.ID}}">
|
||||
<td><input type="checkbox" class="row-pick" aria-label="选择这条"></td>
|
||||
<td><code>{{.ID}}</code></td>
|
||||
<td>{{if eq .Kind "street"}}<span class="kind street">{{.Kind}}</span>{{else}}<span class="kind">{{.Kind}}</span>{{end}}</td>
|
||||
<td>{{.Title}}</td>
|
||||
<td class="muted">{{.Subtitle}}</td>
|
||||
<td>{{.ImageCount}}</td>
|
||||
<td><span class="badge {{.Status}}">{{.Status}}</span></td>
|
||||
<td><a class="view" href="/admin/reviews/{{.Kind}}/{{.ID}}">查看/审核</a>{{if eq .Status "pending"}} · <button type="button" class="btn" data-quick-approve title="按当前内容直接晋升到正式表">通过</button>{{end}}</td>
|
||||
</tr>{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{template "pager" .Pager}}
|
||||
|
||||
<div class="batchbar" id="batchbar" hidden>
|
||||
<span class="muted" id="sel-count">已选 0 条</span>
|
||||
<span class="spacer"></span>
|
||||
<button type="button" id="batch-approve">批量通过</button>
|
||||
<button type="button" id="batch-reject" class="reject">批量驳回…</button>
|
||||
<button type="button" id="batch-clear" class="ghost">清空选择</button>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
13
internal/handler/templates/pages/runway-detail.html
Normal file
13
internal/handler/templates/pages/runway-detail.html
Normal file
@ -0,0 +1,13 @@
|
||||
{{define "title"}}走秀详情 · 管理后台{{end}}
|
||||
{{define "barLabel"}}管理后台 · 走秀详情{{end}}
|
||||
{{define "barRight"}}<a href="/admin/runways">返回列表</a> · <a href="/admin/runways/{{.Article.UID}}/edit">编辑</a> · <a href="/admin/logout">退出</a>{{end}}
|
||||
{{define "content"}}
|
||||
{{template "bar" .}}
|
||||
<div class="main">
|
||||
<p class="muted">编码 {{.Article.UID}} · 品牌 {{.Article.BrandName}}</p>
|
||||
<h1>{{.Article.Title}}</h1>
|
||||
<div class="grid">
|
||||
{{range .Article.Images}}<div class="cell"><button class="thumb" type="button" data-zoom><img src="{{.Image}}" loading="lazy"></button><span>{{.Name}}</span></div>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
32
internal/handler/templates/pages/runway-edit.html
Normal file
32
internal/handler/templates/pages/runway-edit.html
Normal file
@ -0,0 +1,32 @@
|
||||
{{define "title"}}编辑走秀 · 管理后台{{end}}
|
||||
{{define "barLabel"}}管理后台 · 编辑走秀 {{.UID}}{{end}}
|
||||
{{define "barRight"}}<a href="/admin/runways/{{.UID}}">返回详情</a> · <a href="/admin/logout">退出</a>{{end}}
|
||||
{{define "content"}}
|
||||
{{template "bar" .}}
|
||||
<div class="main">
|
||||
<p class="muted">品牌 {{.BrandName}}{{if .IsDown}} · <span class="down">已下架</span>{{end}}</p>
|
||||
<form method="post" action="/admin/runways/{{.UID}}/edit">
|
||||
<div class="row"><div><label>英文标题</label><input name="title_en" value="{{.Runway.TitleEn}}"></div><div><label>中文标题</label><input name="title_cn" value="{{.Runway.TitleCn}}"></div></div>
|
||||
<div class="row"><div><label>英文描述</label><textarea name="description_en">{{.Runway.DescriptionEn}}</textarea></div><div><label>中文描述</label><textarea name="description_cn">{{.Runway.DescriptionCn}}</textarea></div></div>
|
||||
<div class="row"><div><label>年份</label><input name="year" value="{{.Runway.Year}}"></div><div><label>季节</label><input name="season" value="{{.Runway.Season}}"></div></div>
|
||||
<div class="row"><div><label>系列 (collection_type)</label><input name="collection_type" value="{{.Runway.CollectionType}}"></div><div><label>季节码 (season_code)</label><input name="season_code" value="{{.Runway.SeasonCode}}"></div></div>
|
||||
<button type="submit">保存字段</button>
|
||||
</form>
|
||||
|
||||
<h2>图片管理({{len .Images}} 张)</h2>
|
||||
<div class="grid">
|
||||
{{range .Images}}<div class="cell">
|
||||
<button class="thumb" type="button" data-zoom><img src="{{.Image}}" loading="lazy"></button>
|
||||
<div class="acts">
|
||||
<form method="post" action="/admin/runways/{{$.UID}}/cover"><input type="hidden" name="image" value="{{.Image}}"><button type="submit">设封面</button></form>
|
||||
<form method="post" action="/admin/runways/{{$.UID}}/images/{{.ID}}/delete"><button type="submit" class="reject">删除</button></form>
|
||||
</div>
|
||||
</div>{{end}}
|
||||
</div>
|
||||
|
||||
<form method="post" action="/admin/runways/{{.UID}}/toggle" style="margin-top:22px">
|
||||
{{if .IsDown}}<input type="hidden" name="deleted" value="0"><button type="submit">重新上架</button>{{else}}<input type="hidden" name="deleted" value="1"><button type="submit" class="reject">下架(对外不可见)</button>{{end}}
|
||||
</form>
|
||||
<p class="muted" style="margin-top:10px">下架会级联软删全部图片,并异步把S4孤儿图清理任务入队(按引用计数判定,共享图不误删)。</p>
|
||||
</div>
|
||||
{{end}}
|
||||
39
internal/handler/templates/pages/runways.html
Normal file
39
internal/handler/templates/pages/runways.html
Normal file
@ -0,0 +1,39 @@
|
||||
{{define "title"}}走秀档案 · 管理后台{{end}}
|
||||
{{define "barLabel"}}管理后台 · 走秀档案{{end}}
|
||||
{{define "barRight"}}<a href="/admin/logout">退出</a>{{end}}
|
||||
{{define "content"}}
|
||||
{{template "bar" .}}
|
||||
<div class="main">
|
||||
<h1>走秀列表</h1>
|
||||
<form class="toolbar" method="get" action="/admin/runways">
|
||||
<select name="collection">
|
||||
<option value="" {{if eq .Collection ""}}selected{{end}}>全部系列</option>
|
||||
<option value="rtw" {{if eq .Collection "rtw"}}selected{{end}}>RTW 成衣</option>
|
||||
<option value="menswear" {{if eq .Collection "menswear"}}selected{{end}}>男装</option>
|
||||
<option value="couture" {{if eq .Collection "couture"}}selected{{end}}>高定</option>
|
||||
<option value="resort" {{if eq .Collection "resort"}}selected{{end}}>度假</option>
|
||||
<option value="pre_fall" {{if eq .Collection "pre_fall"}}selected{{end}}>早秋</option>
|
||||
</select>
|
||||
<select name="season">
|
||||
<option value="" {{if eq .Season ""}}selected{{end}}>全部季节</option>
|
||||
<option value="spring" {{if eq .Season "spring"}}selected{{end}}>春夏</option>
|
||||
<option value="fall" {{if eq .Season "fall"}}selected{{end}}>秋冬</option>
|
||||
</select>
|
||||
<input name="year" placeholder="年份" value="{{if gt .Year 0}}{{.Year}}{{end}}" style="width:90px">
|
||||
<select name="sort">
|
||||
<option value="" {{if eq .Sort ""}}selected{{end}}>默认排序</option>
|
||||
<option value="year_desc" {{if eq .Sort "year_desc"}}selected{{end}}>年份 ↓</option>
|
||||
<option value="year_asc" {{if eq .Sort "year_asc"}}selected{{end}}>年份 ↑</option>
|
||||
</select>
|
||||
<button type="submit">筛选</button>
|
||||
<a href="/admin/runways">清除</a>
|
||||
</form>
|
||||
<table>
|
||||
<thead><tr><th>编码 ID</th><th>品牌</th><th>标题</th><th>系列</th><th>季节</th><th>年份</th><th>季节码</th><th>图数</th><th></th></tr></thead>
|
||||
<tbody>
|
||||
{{range .Items}}<tr><td><code>{{.UID}}</code></td><td>{{.BrandName}}</td><td>{{.Title}}</td><td>{{.CollectionType}}</td><td>{{.Season}}</td><td>{{.Year}}</td><td>{{.SeasonCode}}</td><td>{{.ImageCount}}</td><td><a class="view" href="/admin/runways/{{.UID}}">查看</a></td></tr>{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{template "pager" .Pager}}
|
||||
</div>
|
||||
{{end}}
|
||||
30
internal/handler/templates/pages/snap-edit.html
Normal file
30
internal/handler/templates/pages/snap-edit.html
Normal file
@ -0,0 +1,30 @@
|
||||
{{define "title"}}编辑街拍 · 管理后台{{end}}
|
||||
{{define "barLabel"}}管理后台 · 编辑街拍 {{.UID}}{{end}}
|
||||
{{define "barRight"}}<a href="/admin/street-snaps/{{.UID}}">返回详情</a> · <a href="/admin/logout">退出</a>{{end}}
|
||||
{{define "content"}}
|
||||
{{template "bar" .}}
|
||||
<div class="main">
|
||||
<p class="muted">{{if .IsDown}}<span class="down">已下架</span>{{end}}</p>
|
||||
<form method="post" action="/admin/street-snaps/{{.UID}}/edit">
|
||||
<div><label>标题</label><input name="title" value="{{.Snap.Title}}"></div>
|
||||
<div class="row"><div><label>年份</label><input name="year" value="{{.Snap.Year}}"></div><div><label>城市</label><input name="city" value="{{.Snap.City}}"></div></div>
|
||||
<button type="submit">保存字段</button>
|
||||
</form>
|
||||
|
||||
<h2>图片管理({{len .Images}} 张)</h2>
|
||||
<div class="grid">
|
||||
{{range .Images}}<div class="cell">
|
||||
<button class="thumb" type="button" data-zoom><img src="{{.Image}}" loading="lazy"></button>
|
||||
<div class="acts">
|
||||
<form method="post" action="/admin/street-snaps/{{$.UID}}/cover"><input type="hidden" name="image" value="{{.Image}}"><button type="submit">设封面</button></form>
|
||||
<form method="post" action="/admin/street-snaps/{{$.UID}}/images/{{.ID}}/delete"><button type="submit" class="reject">删除</button></form>
|
||||
</div>
|
||||
</div>{{end}}
|
||||
</div>
|
||||
|
||||
<form method="post" action="/admin/street-snaps/{{.UID}}/toggle" style="margin-top:22px">
|
||||
{{if .IsDown}}<input type="hidden" name="deleted" value="0"><button type="submit">重新上架</button>{{else}}<input type="hidden" name="deleted" value="1"><button type="submit" class="reject">下架(对外不可见)</button>{{end}}
|
||||
</form>
|
||||
<p class="muted" style="margin-top:10px">下架会级联软删全部图片,并异步把S4孤儿图清理任务入队(按引用计数判定,共享图不误删)。</p>
|
||||
</div>
|
||||
{{end}}
|
||||
13
internal/handler/templates/pages/street-snap-detail.html
Normal file
13
internal/handler/templates/pages/street-snap-detail.html
Normal file
@ -0,0 +1,13 @@
|
||||
{{define "title"}}街拍详情 · 管理后台{{end}}
|
||||
{{define "barLabel"}}管理后台 · 街拍详情{{end}}
|
||||
{{define "barRight"}}<a href="/admin/street-snaps">返回列表</a> · <a href="/admin/street-snaps/{{.Snap.UID}}/edit">编辑</a> · <a href="/admin/logout">退出</a>{{end}}
|
||||
{{define "content"}}
|
||||
{{template "bar" .}}
|
||||
<div class="main">
|
||||
<p class="muted">编码 {{.Snap.UID}}</p>
|
||||
<h1>{{.Snap.Title}}</h1>
|
||||
<div class="grid">
|
||||
{{range .Snap.Images}}<div class="cell"><button class="thumb" type="button" data-zoom><img src="{{.Image}}" loading="lazy"></button><span>{{.Name}}</span></div>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
27
internal/handler/templates/pages/street-snaps.html
Normal file
27
internal/handler/templates/pages/street-snaps.html
Normal file
@ -0,0 +1,27 @@
|
||||
{{define "title"}}街拍 · 管理后台{{end}}
|
||||
{{define "barLabel"}}管理后台 · 街拍{{end}}
|
||||
{{define "barRight"}}<a href="/admin/logout">退出</a>{{end}}
|
||||
{{define "content"}}
|
||||
{{template "bar" .}}
|
||||
<div class="main">
|
||||
<h1>街拍列表</h1>
|
||||
<form class="toolbar" method="get" action="/admin/street-snaps">
|
||||
<input name="city" placeholder="城市" value="{{.City}}">
|
||||
<input name="year" placeholder="年份" value="{{if gt .Year 0}}{{.Year}}{{end}}" style="width:90px">
|
||||
<select name="sort">
|
||||
<option value="" {{if eq .Sort ""}}selected{{end}}>默认(图最多)</option>
|
||||
<option value="year_desc" {{if eq .Sort "year_desc"}}selected{{end}}>年份 ↓</option>
|
||||
<option value="year_asc" {{if eq .Sort "year_asc"}}selected{{end}}>年份 ↑</option>
|
||||
</select>
|
||||
<button type="submit">筛选</button>
|
||||
<a href="/admin/street-snaps">清除</a>
|
||||
</form>
|
||||
<table>
|
||||
<thead><tr><th>编码 ID</th><th>标题</th><th>图片数</th><th></th></tr></thead>
|
||||
<tbody>
|
||||
{{range .Items}}<tr><td><code>{{.UID}}</code></td><td>{{.Title}}</td><td>{{.ImageCount}}</td><td><a class="view" href="/admin/street-snaps/{{.UID}}">查看</a></td></tr>{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{template "pager" .Pager}}
|
||||
</div>
|
||||
{{end}}
|
||||
30
internal/handler/templates/pages/users.html
Normal file
30
internal/handler/templates/pages/users.html
Normal file
@ -0,0 +1,30 @@
|
||||
{{define "title"}}用户管理 · 管理后台{{end}}
|
||||
{{define "barLabel"}}管理后台 · 用户管理{{end}}
|
||||
{{define "barRight"}}<a href="/admin/logout">退出</a>{{end}}
|
||||
{{define "content"}}
|
||||
{{template "bar" .}}
|
||||
<div class="main">
|
||||
<h1>用户管理({{len .Users}})</h1>
|
||||
<p class="muted">图片质量模型已统一:所有用户(含未登录)看图集详情均走同一高清样式,不再按等级分级。</p>
|
||||
<table>
|
||||
<thead><tr><th>ID</th><th>用户名</th><th>邮箱</th><th>等级</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
{{range .Users}}<tr>
|
||||
<td><code>{{.ID}}</code></td>
|
||||
<td>{{.Username}}</td>
|
||||
<td class="muted">{{.Email}}</td>
|
||||
<td>{{if eq .Tier "vip"}}<span class="badge vip">VIP</span>{{else}}<span class="badge free">FREE</span>{{end}}</td>
|
||||
<td>
|
||||
<form class="tier" method="post" action="/admin/users/{{.ID}}/tier">
|
||||
<select name="tier">
|
||||
<option value="free" {{if eq .Tier "free"}}selected{{end}}>free(普通)</option>
|
||||
<option value="vip" {{if eq .Tier "vip"}}selected{{end}}>vip</option>
|
||||
</select>
|
||||
<button type="submit">保存</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
||||
Reference in New Issue
Block a user