Files
chun_qiu bc5076ee41 feat(v1.11.0): 通行证/深渊模式、淡蓝配色与触控小键盘修复
- 触控小键盘补回 3×4 网格样式:上一版重写 CSS 时漏掉了 .keypad/.key,
  按钮退化成行内小方块;现在恢复 46px 圆角键、⌫/✓ 功能键和「触控」开关态。
- 通行证(原「包赛季」):整段有效期在独立日历上按套餐色连续着色(18% 透明度),
  每一格显示同一个「已完成 / 总单数」(0/1 或 1/1);完成后色块保留并显示 1/1。
  沿用 season_done 记录完成日期,交互动线不变。
- 新增深渊模式:套餐设置周期天数 N 与周期数 X;开通时从开始日排出 X 个 N 天周期,
  结束日 = 开始日 + N×X − 1。周期内任意一天完成即算该周期完成;同一周期重复完成
  不重复计数;撤销该周期最后一条完成打卡会回退计数。独立日历连续着色,每格显示
  同一个「已完成周期 / 总周期数」。
- 全量把「包赛季」改名为「通行证」;套餐表单新增通行证 / 深渊选项,深渊显示 N/X 字段;
  客户开通表单、套餐批量开通、订阅列表、客户订阅卡片、日历待办行同步适配,
  通行证 / 深渊不再显示「追加时长」(提交也会被服务端拒绝)。
- 快速完成 / 批量完成对通行证改为整段完成,对深渊走周期打卡,不再错误地按日写打卡。
- 配色改为淡蓝 / 暗蓝:亮色用暗蓝主色 + 淡蓝纸底,暗色用海军蓝底 + 淡蓝强调;
  默认套餐色改为 #3B6EA5;大屏同步蓝调并修正热力图例与今日数字的对比度。
- 大屏页签排除通行证 / 深渊(它们不计每日热力,避免点开是空日历);「今日待打」
  仍会列出待处理的通行证 / 深渊。
- 数据迁移:packages.abyss / packages.cycle_days / subscriptions.abyss /
  subscriptions.cycle_days,老库启动自动补列。
- 修复手机端整段色块把 7 列日历撑出屏幕:日历改成 minmax(0,1fr),小屏色块缩小。
- 版本号 1.10.0 → 1.11.0。

验证:gofmt / go vet / go test 全绿;亮暗两套、1440 与 390 两档截图走查;
通行证 0/1 → 1/1、深渊 1/4 → 2/4、同周期重复完成不重复计数、撤销回退均实测通过。
2026-10-20 02:33:57 +08:00

162 lines
7.4 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{define "state-chip"}}<span class="chip chip-{{.StateClass}}">{{.StateLabel}}</span>{{end}}
{{define "pager"}}
{{if gt .Pages 1}}
<nav class="pager">
{{if .Prev}}<a class="btn btn-soft btn-sm" href="{{.Prev}}">← 上一页</a>{{else}}<span class="btn btn-soft btn-sm disabled">← 上一页</span>{{end}}
<span class="pager-info">{{.Page}} / {{.Pages}} 页 · 共 {{.Total}} 条</span>
{{if .Next}}<a class="btn btn-soft btn-sm" href="{{.Next}}">下一页 →</a>{{else}}<span class="btn btn-soft btn-sm disabled">下一页 →</span>{{end}}
</nav>
{{end}}
{{end}}
{{define "empty"}}
<div class="empty">
<div class="empty-mark">票</div>
<p>{{.Text}}</p>
{{if .Action}}<a class="btn btn-primary" href="{{.Action}}">{{.ActionText}}</a>{{end}}
</div>
{{end}}
{{define "sub-card"}}
<article class="subcard{{if eq .Status "closed"}} is-closed{{end}}" id="sub-{{.ID}}" style="--tag:{{.PackageColor}}">
<div class="subcard-head">
<span class="tag"></span>
<h3>{{.PackageName}}</h3>
{{template "state-chip" .}}
<span class="unit">{{.UnitLabel}}</span>
</div>
<div class="subcard-body">
<div class="subcard-big">{{.RemainText}}</div>
<div class="subcard-meta">{{.PeriodText}}</div>
{{if .DueText}}<div class="due due-{{.Eval.Level}}">{{.DueText}}</div>{{end}}
<div class="bar"><i style="width:{{.Progress}}%"></i></div>
</div>
<div class="subcard-foot">
{{if ne .Status "closed"}}
{{if .CanCheckinToday}}
<form method="post" action="/subscriptions/{{.ID}}/checkin">
<input type="hidden" name="date" value="{{.Today}}">
<input type="hidden" name="status" value="done">
<button class="btn btn-primary btn-sm">今日打卡</button>
</form>
{{end}}
{{if .Abyss}}
{{if .CanAbyssToday}}
<form method="post" action="/subscriptions/{{.ID}}/checkin">
<input type="hidden" name="date" value="{{.Today}}">
<input type="hidden" name="status" value="done">
<button class="btn btn-primary btn-sm">完成本周期</button>
</form>
{{end}}
<span class="chip chip-active">已完成 {{.UsedCount}} / {{.TotalCount}} 周期</span>
{{else if .Season}}
{{if .CanPassToday}}
<form method="post" action="/subscriptions/{{.ID}}/season-done" data-confirm="标记后整段通行证完成,确认?">
<input type="hidden" name="date" value="{{.Today}}">
<button class="btn btn-primary btn-sm">完成通行证</button>
</form>
{{else if .SeasonDone}}
<span class="chip chip-active">通行证已完成 {{.SeasonDone}}</span>
{{else}}
<span class="chip chip-plain">不在通行证有效期</span>
{{end}}
{{else}}
<a class="btn btn-soft btn-sm" href="?extend={{.ID}}#extend">{{if eq .Unit "day"}}追加时长{{else}}追加次数{{end}}</a>
{{end}}
{{if eq .Status "active"}}
<form method="post" action="/subscriptions/{{.ID}}/pause" data-confirm="暂停后剩余时长冻结,确认暂停?">
<button class="btn btn-soft btn-sm">暂停</button>
</form>
{{else if eq .Status "paused"}}
<form method="post" action="/subscriptions/{{.ID}}/resume">
<button class="btn btn-soft btn-sm">恢复</button>
</form>
{{end}}
<form method="post" action="/subscriptions/{{.ID}}/close" data-confirm="结束后该订阅不再出现在待打清单,确认结束?">
<button class="btn btn-ghost btn-sm">结束</button>
</form>
{{else}}
<form method="post" action="/subscriptions/{{.ID}}/reopen">
<button class="btn btn-soft btn-sm">重新启用</button>
</form>
<form method="post" action="/subscriptions/{{.ID}}/delete" data-confirm="将永久删除该订阅及其打卡/追加记录,无法恢复。确定删除?">
<input type="hidden" name="confirm" value="delete">
<button class="btn btn-ghost btn-sm text-danger">删除</button>
</form>
{{end}}
</div>
</article>
{{end}}
{{define "extend-panel"}}
<section class="extend" id="extend" style="--tag:{{.Sub.PackageColor}}">
<header class="extend-head">
<div>
<h3>给 {{.Sub.CustomerTail}} {{.Sub.CustomerName}} 追加{{if .IsDay}}时长{{else}}次数{{end}}</h3>
<p>{{.Sub.PackageName}} · {{.View.RemainText}} · {{.View.PeriodText}}</p>
</div>
<a class="extend-close" href="{{.Back}}" aria-label="关闭">×</a>
</header>
{{if .IsDay}}
<form method="post" action="/subscriptions/{{.Sub.ID}}/extend" class="extend-form"
data-extend data-base="{{.Base}}" data-old-end="{{.OldEnd}}" data-today="{{.Today}}">
<input type="hidden" name="back" value="{{.Back}}">
<input type="hidden" name="new_end_date" value="{{.Suggested}}" data-end-input>
<div class="extend-preview">
<div><span>计算起点</span><b data-base-label>{{.Base}}</b></div>
<div><span>原结束日</span><b>{{.OldEnd}}</b></div>
<div><span>新结束日</span><b data-end-label>{{.Suggested}}</b></div>
<div class="add"><span>本次追加</span><b><i data-days>{{.SuggestedDays}}</i> 天</b></div>
<div><span>追加后剩余</span><b><i data-remain>—</i> 天</b></div>
</div>
<p class="extend-hint">在下面的日历上点选新的终止日期;未到期的订阅从原结束日次日起算,已到期的从今天起算。</p>
<div class="minis">
{{range .Months}}
<div class="minimonth">
<div class="minimonth-title">{{.Title}}</div>
<div class="minimonth-grid">
<span class="dow">一</span><span class="dow">二</span><span class="dow">三</span><span class="dow">四</span><span class="dow">五</span><span class="dow">六</span><span class="dow">日</span>
{{range .Weeks}}{{range .}}
<button type="button" class="miniday{{if not .InMonth}} out{{end}}{{if .IsOldEnd}} old{{end}}{{if .IsToday}} today{{end}}" data-date="{{.Date}}"{{if .Disabled}} disabled{{end}}>{{.Day}}</button>
{{end}}{{end}}
</div>
</div>
{{end}}
</div>
<label class="field"><span>备注</span>
<input type="text" name="note" maxlength="120" placeholder="例如:微信转账 30 天 / 补送 3 天">
</label>
<div class="actions">
<button type="submit" class="btn btn-primary">确认追加</button>
<a class="btn btn-soft" href="{{.Back}}">取消</a>
</div>
</form>
{{else}}
<form method="post" action="/subscriptions/{{.Sub.ID}}/extend" class="extend-form">
<input type="hidden" name="back" value="{{.Back}}">
<div class="extend-preview">
<div><span>当前剩余</span><b>{{.View.RemainText}}</b></div>
<div><span>已用 / 总数</span><b>{{.Sub.UsedCount}} / {{.Sub.TotalCount}}</b></div>
{{if .Sub.EndDate}}<div><span>有效期至</span><b>{{.Sub.EndDate}}</b></div>{{end}}
</div>
<div class="grid-2">
<label class="field"><span>追加次数</span>
<input type="number" name="add_count" min="1" max="10000" value="{{.DefaultAmount}}" required>
</label>
<label class="field"><span>新的有效期(留空不改)</span>
<input type="date" name="new_end_opt">
</label>
</div>
<label class="field"><span>备注</span>
<input type="text" name="note" maxlength="120" placeholder="例如:加购 10 次副本">
</label>
<div class="actions">
<button type="submit" class="btn btn-primary">确认追加</button>
<a class="btn btn-soft" href="{{.Back}}">取消</a>
</div>
</form>
{{end}}
</section>
{{end}}