feat(v1.11.5-L): lite 精简版——移除大屏/客户自查/多用户/小键盘,套餐仅保留按日
需求与确认(用户逐项确认): - 老数据「按次 / 通行证 / 深渊」统一迁移成按日,代码里彻底删除三种模式 - 打手归属一并移除(只剩一个人,颜色与指派没有区分意义) - 盲水印做成完全不可见:只存在于 DOM / 源码,肉眼与截图都看不到 - 拼写采用更正后的 Powered by Baka春秋 - 版本号与品牌全站统一带 -L - screen_public / portal_public 保留解析但不起作用,保证旧 ini 能直接启动 - README 同步更新 品牌与版本(全站统一): - const version = "1.11.5-L":<title>、启动横幅、日志前缀 [代打台-L]、 设置页版本号、页脚版本号全部带 -L - 左上角导航品牌 代打台 → 代打台-L(登录页、初始化页同步) - 页脚新增可见署名 Powered by Baka春秋 盲水印: - _layout.html 在 <body> 起始处注入 .wm-blind 容器(含注释与 data-wm 双标记), 覆盖包括登录/初始化在内的所有页面 - app.css 用零尺寸 + 透明 + opacity:0 + clip-path:inset(50%) 四重隐藏, 同时留同名注释;不占位、不上色、不进无障碍树、不影响打印 功能移除: - 大屏:删除 handlers_screen.go、pages/screen.html、_screen_layout.html、 static/screen.css、static/screen.js、store.Stats/ScreenStats; 导航「大屏 ↗」、页脚「大屏」、设置页「大屏刷新/大屏」行、启动横幅大屏行一并删除 - 客户自查:删除 handlers_portal.go、pages/portal.html 与 .portal-*/.pcal-* 样式, 设置页「客户自助」行删除 - 多管理员:删除 handleUserCreate/Toggle/Color/UserEditPage/UserEditSave、 pages/user_form.html、store 侧 ActiveUsers/SetUserColor/SetUserActive/ UpdateUserByAdmin/NormalizeColor/AssigneePalette;设置页「管理员」整块移除, 只保留首次启动创建的那一个账户与「修改我的密码」 - 打手归属:删除 customers.assignee_id 相关读写与 UI(客户详情指派下拉、 客户表单「归属打手」、日历格左侧打手色竖条、任务卡打手标签、套餐详情客户列) - 登录页与初始化页的说明文案同步改为单账户口径(「只有一个管理员账户」 「创建后不能再添加其他管理员」),字数与 main 对齐,卡片不换行、高度不变 - 触摸小键盘:删除 3×4 键盘、⌨/触控开关、localStorage 记忆、.keypad* 样式 - 套餐计费方式:只保留按日。删除按次/通行证/深渊的 Package 与 Subscription 字段、 domain 里的 UnitCount/StateUsedUp/CycleIndex、package_form 计费方式单选与 通行证/深渊/有效期字段、日历整段色块(has-block/cell-block/season-band)、 追加次数分支、SeasonComplete/AddCount、CountActiveSubs 的次数条件 数据库迁移(幂等,Migrate 内自动执行): - normalizeLegacyData:套餐一律 unit='day' 并清 season/abyss/cycle_days/ default_validity_days/season_*;订阅清 season/abyss/cycle_days/season_done - 通行证、深渊当年就是 unit='day' 且起止日完整,仅清标记,服务区间原样保留 - 按次按「1 次 = 1 天」折算:结束日 = 开始日 + 总次数 − 1;仍缺结束日退回开始日 - 只动数据,不删表不删列:老库的 season/abyss/cycle_days/total_count/used_count 保留但不再使用,升级可逆、不会因为 DDL 失败卡住 - 新库 schema 干净:不再创建上述列,users.color / customers.assignee_id 也不创建 - 老库 ensureColumn 保留 calendar_separate / tag / archived 三项(真增量列) 兼容: - config 仍解析 screen_public / portal_public(结构体字段注明已废弃), 默认 ini 模板里改为「已废弃,写了不报错、不生效」 测试: - go vet ./... 通过;go test ./... 全部通过 (新增 TestNormalizeLegacyTypeData 验证三模式折算成按日; TestSingleUserAccount / TestSessionLifecycle 覆盖单用户与会话; 删除按次、深渊、打手颜色、多用户等已不存在的能力的用例) - 新增 scripts/smoke-lite.ps1:起隔离实例,19 个页面级请求全部 200, 已移除的 /screen、/customer、/api/screen/day 均 404, 水印/品牌/v1.11.5-L/无残留词 12 项断言通过, 真实数据下日历出现待打任务、「剩 30 天」、今天到期徽标 4 项断言通过, 本次 0 失败 README:改为 lite 版说明,删除大屏/客户自查/通行证/深渊/按次/小键盘/多用户章节, 新增「盲水印」与「与 main 分支的差异」两节(含老数据折算规则与列保留说明)。
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<title>{{.Title}} · 代打台</title>
|
||||
<title>{{.Title}} · 代打台-L</title>
|
||||
<link rel="icon" href="/static/favicon.svg?v={{.AssetVersion}}" type="image/svg+xml">
|
||||
<script>
|
||||
/* 首屏主题:服务端没有写 data-bs-theme 时(还没选过主题)跟随系统,避免闪白 */
|
||||
@@ -19,10 +19,12 @@
|
||||
<link rel="stylesheet" href="/static/app.css?v={{.AssetVersion}}">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Powered by Baka春秋 · 代打台-L 盲水印(不可见,勿删) -->
|
||||
<div class="wm-blind" aria-hidden="true" data-wm="Powered by Baka春秋" hidden-mark="Powered by Baka春秋">Powered by Baka春秋</div>
|
||||
{{if .User}}
|
||||
<nav class="navbar navbar-expand-xl app-navbar sticky-top">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="/calendar"><span class="brand-mark" aria-hidden="true">代</span><span>代打台</span></a>
|
||||
<a class="navbar-brand" href="/calendar"><span class="brand-mark" aria-hidden="true">代</span><span>代打台-L</span></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#mainNav" aria-controls="mainNav" aria-expanded="false" aria-label="展开导航"><span class="navbar-toggler-icon"></span></button>
|
||||
<div class="collapse navbar-collapse" id="mainNav">
|
||||
<ul class="navbar-nav me-auto">
|
||||
@@ -30,7 +32,6 @@
|
||||
<li class="nav-item"><a class="nav-link{{if eq .Nav "customers"}} active{{end}}" href="/customers">客户</a></li>
|
||||
<li class="nav-item"><a class="nav-link{{if eq .Nav "subscriptions"}} active{{end}}" href="/subscriptions">订阅</a></li>
|
||||
<li class="nav-item"><a class="nav-link{{if eq .Nav "packages"}} active{{end}}" href="/packages">套餐</a></li>
|
||||
<li class="nav-item"><a class="nav-link nav-screen" href="/screen" target="_blank" rel="noopener">大屏 ↗</a></li>
|
||||
</ul>
|
||||
<form class="nav-search" role="search" action="/customers" method="get">
|
||||
<input class="form-control form-control-sm" type="search" name="q" value="{{.Query}}" placeholder="手机尾号 / 姓名 / 游戏名" aria-label="搜索客户" data-search>
|
||||
@@ -59,10 +60,10 @@
|
||||
{{if .Error}}<div class="notice notice-danger" role="alert">{{.Error}}</div>{{end}}
|
||||
<main class="{{if .User}}app-main{{else}}auth-main{{end}}">{{template "content" .}}</main>
|
||||
{{if .User}}<footer class="app-foot">
|
||||
<span>代打台 <span class="foot-version">v{{.Version}}</span></span>
|
||||
<span>代打台-L <span class="foot-version">v{{.Version}}</span></span>
|
||||
<span class="foot-by">Powered by Baka春秋</span>
|
||||
<a href="/logs">操作日志</a>
|
||||
<a href="/settings">设置</a>
|
||||
<a href="/screen" target="_blank" rel="noopener">大屏</a>
|
||||
</footer>{{end}}
|
||||
<script src="/static/vendor/bootstrap.bundle.min.js?v={{.AssetVersion}}" defer></script>
|
||||
<script src="/static/app.js?v={{.AssetVersion}}" defer></script>
|
||||
|
||||
@@ -41,29 +41,7 @@
|
||||
<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}}
|
||||
<a class="btn btn-soft btn-sm" href="?extend={{.ID}}#extend">追加时长</a>
|
||||
{{if eq .Status "active"}}
|
||||
<form method="post" action="/subscriptions/{{.ID}}/pause" data-confirm="暂停后剩余时长冻结,确认暂停?">
|
||||
<button class="btn btn-soft btn-sm">暂停</button>
|
||||
@@ -93,12 +71,11 @@
|
||||
<section class="extend" id="extend" style="--tag:{{.Sub.PackageColor}}">
|
||||
<header class="extend-head">
|
||||
<div>
|
||||
<h3>给 {{.Sub.CustomerTail}} {{.Sub.CustomerName}} 追加{{if .IsDay}}时长{{else}}次数{{end}}</h3>
|
||||
<h3>给 {{.Sub.CustomerTail}} {{.Sub.CustomerName}} 追加时长</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}}">
|
||||
@@ -132,30 +109,5 @@
|
||||
<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}}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
{{define "screenlayout"}}<!doctype html>
|
||||
<html lang="zh-CN" data-bs-theme="{{if eq .Theme "light"}}light{{else}}dark{{end}}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<meta http-equiv="refresh" content="{{.D.Refresh}}">
|
||||
<title>{{.Title}} · 代打台</title>
|
||||
<link rel="icon" href="/static/favicon.svg?v={{.D.AssetVersion}}" type="image/svg+xml">
|
||||
<link rel="stylesheet" href="/static/vendor/bootstrap.min.css?v={{.D.AssetVersion}}">
|
||||
<link rel="stylesheet" href="/static/screen.css?v={{.D.AssetVersion}}">
|
||||
</head>
|
||||
<body class="screen-body">
|
||||
{{template "content" .}}
|
||||
<script src="/static/vendor/bootstrap.bundle.min.js?v={{.D.AssetVersion}}" defer></script>
|
||||
<script src="/static/screen.js?v={{.D.AssetVersion}}" defer></script>
|
||||
</body>
|
||||
</html>{{end}}
|
||||
@@ -40,9 +40,8 @@
|
||||
{{range .D.Weeks}}
|
||||
<div class="cal-week" role="row">
|
||||
{{range .}}
|
||||
<a class="cal-cell heat-{{.Heat}}{{if not .InMonth}} out{{end}}{{if .IsToday}} today{{end}}{{if .IsSelected}} sel{{end}}{{if .IsWeekend}} weekend{{end}}{{if .DueCount}} has-due{{end}}{{if .BlockColor}} has-block{{end}}"
|
||||
href="/calendar?y={{$.D.Year}}&m={{$.D.Month}}&d={{.Date}}&{{$.D.FilterQuery}}" role="gridcell"{{if .BlockColor}} style="--block:{{.BlockColor}};--block-pct:{{.BlockPercent}}%"{{end}}>
|
||||
{{if .Strip}}<span class="asg-strip" aria-hidden="true">{{range .Strip}}<i style="background:{{.}}"></i>{{end}}</span>{{end}}
|
||||
<a class="cal-cell heat-{{.Heat}}{{if not .InMonth}} out{{end}}{{if .IsToday}} today{{end}}{{if .IsSelected}} sel{{end}}{{if .IsWeekend}} weekend{{end}}{{if .DueCount}} has-due{{end}}"
|
||||
href="/calendar?y={{$.D.Year}}&m={{$.D.Month}}&d={{.Date}}&{{$.D.FilterQuery}}" role="gridcell">
|
||||
<div class="cell-top">
|
||||
<span class="dnum">{{.Day}}</span>
|
||||
<span class="cell-badges">
|
||||
@@ -50,7 +49,6 @@
|
||||
{{if .DueCount}}<span class="due-badge"><em>到期</em>{{.DueCount}}</span>{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{if .BlockText}}<span class="cell-block" title="{{.BlockTitle}}">{{.BlockText}}</span>{{end}}
|
||||
{{if .TaskCount}}
|
||||
<div class="cell-count">
|
||||
<b>{{.DoneCount}}</b><span>/ {{.TaskCount}}</span>
|
||||
@@ -85,23 +83,8 @@
|
||||
<input type="hidden" name="back" value="{{.D.Back}}">
|
||||
<input class="form-control form-control-sm" type="text" name="tail" placeholder="输入手机尾号,回车即可完成" maxlength="8" autocomplete="off" inputmode="numeric" aria-label="手机尾号快速完成">
|
||||
<button class="btn btn-sm btn-primary" type="submit">完成</button>
|
||||
<button type="button" class="btn btn-sm btn-ghost keypad-toggle" data-keypad-toggle title="切换触控/PC 模式" aria-label="切换触控/PC 模式">⌨</button>
|
||||
</form>
|
||||
<p class="muted small quick-hint">唯一匹配直接完成;同尾号多人 / 一单多服务会列出让你勾选。</p>
|
||||
<div class="keypad" data-keypad role="group" aria-label="数字小键盘" hidden>
|
||||
<button type="button" class="key" data-key="1">1</button>
|
||||
<button type="button" class="key" data-key="2">2</button>
|
||||
<button type="button" class="key" data-key="3">3</button>
|
||||
<button type="button" class="key" data-key="4">4</button>
|
||||
<button type="button" class="key" data-key="5">5</button>
|
||||
<button type="button" class="key" data-key="6">6</button>
|
||||
<button type="button" class="key" data-key="7">7</button>
|
||||
<button type="button" class="key" data-key="8">8</button>
|
||||
<button type="button" class="key" data-key="9">9</button>
|
||||
<button type="button" class="key key-fn" data-key="back" aria-label="退格">⌫</button>
|
||||
<button type="button" class="key" data-key="0">0</button>
|
||||
<button type="button" class="key key-ok" data-key="ok" aria-label="确认完成">✓</button>
|
||||
</div>
|
||||
|
||||
{{if .D.PickTail}}
|
||||
<section class="picker">
|
||||
@@ -142,7 +125,7 @@
|
||||
<ul class="list-group list-group-flush task-list">
|
||||
{{range .D.Tasks}}
|
||||
{{if or .Done .Skipped}}
|
||||
<li class="list-group-item task task-done px-0" style="--asg:{{.AssigneeHex}}">
|
||||
<li class="list-group-item task task-done px-0">
|
||||
<details class="done-fold">
|
||||
<summary>
|
||||
<span class="ticket" style="--tag:{{.PackageColor}}"><b>{{.CustomerTail}}</b>{{.CustomerName}}</span>
|
||||
@@ -153,7 +136,6 @@
|
||||
</summary>
|
||||
<div class="done-detail">
|
||||
<div class="task-meta">
|
||||
<span class="asg{{if .AssigneeNone}} none{{end}}"><i style="background:{{.AssigneeHex}}"></i>{{.AssigneeLabel}}</span>
|
||||
<span>{{.RemainText}}</span>
|
||||
{{if .DueText}}<span class="due due-{{.Eval.Level}}">{{.DueText}}</span>{{end}}
|
||||
</div>
|
||||
@@ -173,7 +155,7 @@
|
||||
<input type="hidden" name="back" value="{{$.D.Back}}">
|
||||
<button class="btn btn-sm {{if .Urgent}}btn-urgent{{else}}btn-ghost{{end}}" type="submit">{{if .Urgent}}取消加急{{else}}标记加急{{end}}</button>
|
||||
</form>
|
||||
{{if not (or .Season .Abyss)}}<a class="btn btn-soft btn-sm" href="/calendar?y={{$.D.Year}}&m={{$.D.Month}}&d={{$.D.Selected}}&{{$.D.FilterQuery}}&extend={{.ID}}#extend">追加时长</a>{{end}}
|
||||
<a class="btn btn-soft btn-sm" href="/calendar?y={{$.D.Year}}&m={{$.D.Month}}&d={{$.D.Selected}}&{{$.D.FilterQuery}}&extend={{.ID}}#extend">追加时长</a>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
@@ -181,7 +163,7 @@
|
||||
</details>
|
||||
</li>
|
||||
{{else}}
|
||||
<li class="list-group-item task{{if .Urgent}} urgent{{end}} px-0" style="--asg:{{.AssigneeHex}}">
|
||||
<li class="list-group-item task{{if .Urgent}} urgent{{end}} px-0">
|
||||
<div class="task-main">
|
||||
<a class="task-title" href="/customers/{{.CustomerID}}">
|
||||
<span class="ticket" style="--tag:{{.PackageColor}}"><b>{{.CustomerTail}}</b>{{.CustomerName}}</span>
|
||||
@@ -189,7 +171,6 @@
|
||||
{{if .Urgent}}<span class="tag-urgent">加急</span>{{end}}
|
||||
</a>
|
||||
<div class="task-meta">
|
||||
<span class="asg{{if .AssigneeNone}} none{{end}}"><i style="background:{{.AssigneeHex}}"></i>{{.AssigneeLabel}}</span>
|
||||
<span>{{.RemainText}}</span>
|
||||
{{if .DueText}}<span class="due due-{{.Eval.Level}}">{{.DueText}}</span>{{end}}
|
||||
</div>
|
||||
@@ -205,14 +186,12 @@
|
||||
<details class="more-actions">
|
||||
<summary class="btn btn-sm btn-ghost" title="更多操作" aria-label="更多操作">⋯</summary>
|
||||
<div class="more-menu">
|
||||
{{if not .Season}}
|
||||
<form method="post" action="/subscriptions/{{.ID}}/checkin">
|
||||
<input type="hidden" name="date" value="{{$.D.Selected}}">
|
||||
<input type="hidden" name="status" value="skipped">
|
||||
<input type="hidden" name="back" value="{{$.D.Back}}">
|
||||
<button class="btn btn-sm btn-ghost" type="submit">跳过这次</button>
|
||||
</form>
|
||||
{{end}}
|
||||
<form method="post" action="/tasks/urgent">
|
||||
<input type="hidden" name="sub_id" value="{{.ID}}">
|
||||
<input type="hidden" name="date" value="{{$.D.Selected}}">
|
||||
@@ -220,7 +199,7 @@
|
||||
<input type="hidden" name="back" value="{{$.D.Back}}">
|
||||
<button class="btn btn-sm {{if .Urgent}}btn-urgent{{else}}btn-ghost{{end}}" type="submit">{{if .Urgent}}取消加急{{else}}标记加急{{end}}</button>
|
||||
</form>
|
||||
{{if not (or .Season .Abyss)}}<a class="btn btn-soft btn-sm" href="/calendar?y={{$.D.Year}}&m={{$.D.Month}}&d={{$.D.Selected}}&{{$.D.FilterQuery}}&extend={{.ID}}#extend">追加时长</a>{{end}}
|
||||
<a class="btn btn-soft btn-sm" href="/calendar?y={{$.D.Year}}&m={{$.D.Month}}&d={{$.D.Selected}}&{{$.D.FilterQuery}}&extend={{.ID}}#extend">追加时长</a>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
@@ -11,18 +11,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-actions">
|
||||
<form method="post" action="/customers/{{.D.Customer.ID}}/assignee" class="assign-form">
|
||||
<select name="assignee_id" aria-label="归属打手">
|
||||
<option value="0">未指派</option>
|
||||
{{range .D.Users}}<option value="{{.ID}}"{{if eq $.D.Customer.AssigneeID .ID}} selected{{end}}>{{if .DisplayName}}{{.DisplayName}}{{else}}{{.Username}}{{end}}</option>{{end}}
|
||||
</select>
|
||||
<button class="btn btn-soft btn-sm" type="submit">保存打手</button>
|
||||
</form>
|
||||
<a class="btn btn-soft" href="/customers/{{.D.Customer.ID}}/edit">编辑资料</a>
|
||||
{{if .D.Customer.Archived}}
|
||||
<form method="post" action="/customers/{{.D.Customer.ID}}/restore"><button class="btn btn-soft" type="submit">恢复客户</button></form>
|
||||
{{else}}
|
||||
<form method="post" action="/customers/{{.D.Customer.ID}}/archive" data-confirm="停用后该客户不再出现在日历和大屏,订阅会保留。确定停用?"><button class="btn btn-ghost" type="submit">停用客户</button></form>
|
||||
<form method="post" action="/customers/{{.D.Customer.ID}}/archive" data-confirm="停用后该客户不再出现在日历,订阅会保留。确定停用?"><button class="btn btn-ghost" type="submit">停用客户</button></form>
|
||||
{{end}}
|
||||
<form method="post" action="/customers/{{.D.Customer.ID}}/delete" data-confirm="将永久删除该客户及其全部订阅、打卡与追加记录,无法恢复。确定删除?">
|
||||
<input type="hidden" name="confirm" value="delete">
|
||||
@@ -35,9 +28,6 @@
|
||||
{{if .D.Customer.GameServer}}<div><dt>区服</dt><dd>{{.D.Customer.GameServer}}</dd></div>{{end}}
|
||||
{{if .D.Customer.Contact}}<div><dt>联系</dt><dd>{{.D.Customer.Contact}}</dd></div>{{end}}
|
||||
{{if .D.Customer.Source}}<div><dt>来源</dt><dd>{{.D.Customer.Source}}</dd></div>{{end}}
|
||||
<div><dt>打手</dt><dd>
|
||||
<span class="asg{{if eq .D.Customer.AssigneeID 0}} none{{end}}"><i style="background:{{if .D.Customer.AssigneeColor}}{{.D.Customer.AssigneeColor}}{{else}}#8A8F98{{end}}"></i>{{if .D.Customer.AssigneeName}}{{.D.Customer.AssigneeName}}{{else}}未指派{{end}}</span>
|
||||
</dd></div>
|
||||
<div><dt>建档</dt><dd>{{.D.Customer.CreatedAt}}</dd></div>
|
||||
</dl>
|
||||
</header>
|
||||
@@ -89,23 +79,17 @@
|
||||
<select class="form-select form-select-sm" name="package_id" required data-pkg-select aria-label="选择套餐">
|
||||
<option value="">选择套餐…</option>
|
||||
{{range .D.Packages}}
|
||||
<option value="{{.ID}}" data-unit="{{if .Season}}season{{else if .Abyss}}abyss{{else}}{{.Unit}}{{end}}" data-amount="{{.DefaultAmount}}" data-validity="{{.DefaultValidityDays}}"{{if .Archived}} disabled{{end}}{{if .SeasonExpired $.TodayStr}} disabled{{end}}>
|
||||
{{.Name}} · {{.UnitLabel}} {{if .Season}}{{.SeasonStart}}~{{.SeasonEnd}}{{else if .Abyss}}{{.CycleDays}} 天/周期 × {{.DefaultAmount}} 周期{{else}}{{.DefaultAmount}}{{if eq .Unit "day"}}天{{else}}次{{end}}{{end}}{{if .SeasonExpired $.TodayStr}}(通行证已结束){{end}}{{if .Archived}}(已归档){{end}}
|
||||
<option value="{{.ID}}" data-amount="{{.DefaultAmount}}"{{if .Archived}} disabled{{end}}>
|
||||
{{.Name}} · {{.UnitLabel}} {{.DefaultAmount}} 天{{if .Archived}}(已归档){{end}}
|
||||
</option>
|
||||
{{end}}
|
||||
</select>
|
||||
<label class="inline-field" data-start-wrap>开始日
|
||||
<input class="form-control form-control-sm" type="date" name="start_date" value="{{.TodayStr}}" required>
|
||||
</label>
|
||||
<label class="inline-field" data-days-wrap>{{/* 默认显示 */}}
|
||||
<label class="inline-field" data-days-wrap>
|
||||
天数 <input class="form-control form-control-sm" type="number" name="days" min="1" max="3650" value="30">
|
||||
</label>
|
||||
<label class="inline-field" data-count-wrap hidden>
|
||||
次数 <input class="form-control form-control-sm" type="number" name="total_count" min="1" max="10000" value="10">
|
||||
</label>
|
||||
<label class="inline-field" data-cycles-wrap hidden>
|
||||
周期数 <input class="form-control form-control-sm" type="number" name="total_count" min="1" max="1000" value="4">
|
||||
</label>
|
||||
<label class="inline-field" data-end-wrap>
|
||||
终止日(可留空)<input class="form-control form-control-sm" type="date" name="end_date">
|
||||
</label>
|
||||
@@ -163,9 +147,7 @@
|
||||
<td class="mono small">{{if .BaseDate}}{{.BaseDate}}{{else}}—{{end}}</td>
|
||||
<td class="mono small">{{if .OldEndDate}}{{.OldEndDate}} → {{end}}{{if .NewEndDate}}{{.NewEndDate}}{{else}}—{{end}}</td>
|
||||
<td class="mono">
|
||||
{{if gt .DaysAdded 0}}<span class="plus">+{{.DaysAdded}} 天</span>{{end}}
|
||||
{{if gt .CountAdded 0}}<span class="plus">+{{.CountAdded}} 次</span>{{end}}
|
||||
{{if and (le .DaysAdded 0) (le .CountAdded 0)}}—{{end}}
|
||||
{{if gt .DaysAdded 0}}<span class="plus">+{{.DaysAdded}} 天</span>{{else}}—{{end}}
|
||||
</td>
|
||||
<td class="small">{{if .Note}}{{.Note}}{{else}}—{{end}}</td>
|
||||
<td class="small">{{if .OperatorName}}{{.OperatorName}}{{else}}—{{end}}</td>
|
||||
|
||||
@@ -29,24 +29,13 @@
|
||||
<label class="field"><span>联系方式</span>
|
||||
<input type="text" name="contact" value="{{.D.Customer.Contact}}" maxlength="64" placeholder="微信 / QQ">
|
||||
</label>
|
||||
<label class="field"><span>归属打手</span>
|
||||
<select name="assignee_id">
|
||||
<option value="0"{{if eq .D.Customer.AssigneeID 0}} selected{{end}}>未指派</option>
|
||||
{{range .D.Users}}
|
||||
<option value="{{.ID}}"{{if eq $.D.Customer.AssigneeID .ID}} selected{{end}}>{{if .DisplayName}}{{.DisplayName}}{{else}}{{.Username}}{{end}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
<small>该客户之后的所有单子都记在这个打手名下</small>
|
||||
</label>
|
||||
</div>
|
||||
<div class="grid-2">
|
||||
<label class="field"><span>来源渠道</span>
|
||||
<input type="text" name="source" value="{{.D.Customer.Source}}" maxlength="32" placeholder="抖音 / 朋友介绍">
|
||||
</label>
|
||||
<label class="field"><span>标签</span>
|
||||
<input type="text" name="tags" value="{{.D.Customer.Tags}}" maxlength="120" placeholder="老客户,包月,难缠(逗号分隔)">
|
||||
</label>
|
||||
</div>
|
||||
<label class="field"><span>标签</span>
|
||||
<input type="text" name="tags" value="{{.D.Customer.Tags}}" maxlength="120" placeholder="老客户,包月,难缠(逗号分隔)">
|
||||
</label>
|
||||
<label class="field"><span>备注</span>
|
||||
<textarea name="note" rows="3" maxlength="500" placeholder="打法偏好、沟通记录等">{{.D.Customer.Note}}</textarea>
|
||||
</label>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<div class="auth">
|
||||
<button class="theme-toggle auth-theme" type="button" data-theme-toggle aria-label="切换亮色/暗色" aria-pressed="false"><span class="ic-moon" aria-hidden="true">☾</span><span class="ic-sun" aria-hidden="true">☀</span></button>
|
||||
<div class="auth-card">
|
||||
<div class="auth-brand"><span class="brand-mark" aria-hidden="true">代</span><span>代打台</span></div>
|
||||
<div class="auth-brand"><span class="brand-mark" aria-hidden="true">代</span><span>代打台-L</span></div>
|
||||
<h1>登录</h1>
|
||||
<p>所有账户均为管理员,任何操作都会留痕。</p>
|
||||
<p>只有一个管理员账户,任何操作都会留痕。</p>
|
||||
<form method="post" action="/login" class="stack">
|
||||
<input type="hidden" name="next" value="{{.Next}}">
|
||||
<label class="field"><span>用户名</span>
|
||||
@@ -15,7 +15,7 @@
|
||||
</label>
|
||||
<button type="submit" class="btn btn-primary btn-block">登录</button>
|
||||
</form>
|
||||
<p class="auth-foot">代打台 · 单文件部署 · 数据只在本机</p>
|
||||
<p class="auth-foot">代打台-L · 单文件部署 · 数据只在本机</p>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div>
|
||||
<h1>{{.D.Package.Name}}</h1>
|
||||
<p>
|
||||
{{.D.Package.UnitLabel}} · {{.D.Package.AmountText}}{{if .D.Package.CycleLabel}} · {{.D.Package.CycleLabel}}{{end}}
|
||||
{{.D.Package.UnitLabel}} · {{.D.Package.AmountText}}
|
||||
{{if .D.Package.Tag}} · 标签「{{.D.Package.Tag}}」{{end}}{{if .D.Package.CalendarSeparate}} · 独立日历{{end}}
|
||||
{{if .D.Package.Archived}}<span class="chip chip-closed">已归档</span>{{end}}
|
||||
</p>
|
||||
@@ -26,21 +26,8 @@
|
||||
|
||||
<form method="post" action="/packages/{{.D.Package.ID}}/subscribe" class="section card">
|
||||
<h2>批量开通</h2>
|
||||
<p class="muted small">勾选客户后一次开通;已经是该套餐的客户会自动跳过。{{if .D.Package.Season}}通行证从套餐区间开始,整段完成。{{else if .D.Package.Abyss}}按周期数开通,结束日自动计算。{{else}}开始日期默认今天,数量默认取套餐设置,可改。{{end}}</p>
|
||||
<p class="muted small">勾选客户后一次开通;已经是该套餐的客户会自动跳过。开始日期默认今天,天数默认取套餐设置,可改。</p>
|
||||
|
||||
{{if .D.Package.Abyss}}
|
||||
<div class="grid-2">
|
||||
<label class="field"><span>开始日期</span>
|
||||
<input type="date" name="start_date" value="{{.D.Today}}" required>
|
||||
</label>
|
||||
<label class="field"><span>周期数</span>
|
||||
<input type="number" name="total_count" min="1" max="1000" value="{{.D.Package.DefaultAmount}}">
|
||||
</label>
|
||||
</div>
|
||||
<p class="muted small">每 {{.D.Package.CycleDays}} 天一个周期,共 {{.D.Package.DefaultAmount}} 个周期;结束日按开始日自动计算。</p>
|
||||
{{else if .D.Package.Season}}
|
||||
<p class="muted small">通行证区间:{{.D.Package.SeasonStart}} → {{.D.Package.SeasonEnd}},开通后整段完成,不再按天排单。</p>
|
||||
{{else if eq .D.Package.Unit "day"}}
|
||||
<div class="grid-auto">
|
||||
<label class="field"><span>开始日期</span>
|
||||
<input type="date" name="start_date" value="{{.D.Today}}" required>
|
||||
@@ -49,19 +36,6 @@
|
||||
<input type="number" name="days" min="1" max="3650" value="{{.D.Package.DefaultAmount}}">
|
||||
</label>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="grid-auto">
|
||||
<label class="field"><span>开始日期</span>
|
||||
<input type="date" name="start_date" value="{{.D.Today}}" required>
|
||||
</label>
|
||||
<label class="field"><span>次数</span>
|
||||
<input type="number" name="total_count" min="1" max="10000" value="{{.D.Package.DefaultAmount}}">
|
||||
</label>
|
||||
<label class="field"><span>到期日(可选)</span>
|
||||
<input type="date" name="end_date">
|
||||
</label>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<div class="table-wrap">
|
||||
<table class="table tight">
|
||||
@@ -77,7 +51,7 @@
|
||||
<tr{{if $subscribed}} class="archived"{{end}}>
|
||||
<td>{{if $subscribed}}<span class="muted small" title="已是此套餐">—</span>{{else}}<input type="checkbox" name="customer_ids" value="{{.ID}}" aria-label="选择 {{.Name}}" checked>{{end}}</td>
|
||||
<td><a class="tail" href="/customers/{{.ID}}">{{.Tail}}</a></td>
|
||||
<td>{{.Name}}{{if .AssigneeName}} <span class="asg"><i style="background:{{.AssigneeColor}}"></i>{{.AssigneeName}}</span>{{end}}</td>
|
||||
<td>{{.Name}}</td>
|
||||
<td class="summary due-{{.Level}}">{{.Summary}}</td>
|
||||
<td>{{if $subscribed}}<span class="chip chip-closed">已是此套餐</span>{{else}}<span class="chip chip-plain">可开通</span>{{end}}</td>
|
||||
</tr>
|
||||
|
||||
@@ -3,51 +3,21 @@
|
||||
<header class="page-head">
|
||||
<div>
|
||||
<h1>{{if .D.IsNew}}新增套餐{{else}}编辑套餐{{end}}</h1>
|
||||
<p>按日套餐用起止日期计算剩余天数;按次套餐记录剩余次数;通行证整段完成;深渊按周期完成。</p>
|
||||
<p>按日套餐用起止日期计算剩余天数;给客户开通时选择开始日与天数即可。</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<form method="post" class="form card" data-package-form
|
||||
action="{{if .D.IsNew}}/packages{{else}}/packages/{{.D.Package.ID}}/edit{{end}}">
|
||||
<label class="field"><span>套餐名称 <i>*</i></span>
|
||||
<input type="text" name="name" required maxlength="32" value="{{.D.Package.Name}}" placeholder="例如 包月日常 / 深渊通行证 / 10 次副本">
|
||||
<input type="text" name="name" required maxlength="32" value="{{.D.Package.Name}}" placeholder="例如 包月日常 / 深渊日常">
|
||||
</label>
|
||||
|
||||
<fieldset class="field">
|
||||
<span>计费方式 <i>*</i></span>
|
||||
<div class="radios">
|
||||
<label><input type="radio" name="unit" value="day"{{if and (eq .D.Package.Unit "day") (not .D.Package.Season) (not .D.Package.Abyss)}} checked{{end}}>
|
||||
<b>按日</b><small>有开始日与结束日,每天一条待打任务,可打卡</small></label>
|
||||
<label><input type="radio" name="unit" value="count"{{if and (eq .D.Package.Unit "count") (not .D.Package.Season) (not .D.Package.Abyss)}} checked{{end}}>
|
||||
<b>按次</b><small>记录剩余次数,排期完成时自动扣 1 次,有效期可选</small></label>
|
||||
<label><input type="radio" name="unit" value="season"{{if .D.Package.Season}} checked{{end}}>
|
||||
<b>通行证</b><small>通行证有效期内整段一次完成;日历上连续着色,每天显示同一个完成数</small></label>
|
||||
<label><input type="radio" name="unit" value="abyss"{{if .D.Package.Abyss}} checked{{end}}>
|
||||
<b>深渊</b><small>N 天一个周期,周期内任意一天完成即算该周期完成;按周期数计数</small></label>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="grid-2" data-season-wrap hidden>
|
||||
<label class="field"><span>通行证开始日 <i>*</i></span><input type="date" name="season_start" value="{{.D.Package.SeasonStart}}"></label>
|
||||
<label class="field"><span>通行证结束日 <i>*</i></span><input type="date" name="season_end" value="{{.D.Package.SeasonEnd}}"></label>
|
||||
</div>
|
||||
|
||||
<div class="field field-narrow" data-abyss-wrap hidden>
|
||||
<span>周期天数 N <i>*</i></span>
|
||||
<input type="number" name="cycle_days" min="1" max="365" value="{{if .D.Package.Abyss}}{{.D.Package.CycleDays}}{{else}}7{{end}}" placeholder="例如 7">
|
||||
<small>N 天一个周期;下方「周期数」填 X。开通后从开始日连续排 X 个周期。</small>
|
||||
</div>
|
||||
|
||||
<div class="field field-narrow" data-validity-wrap hidden>
|
||||
<span>按次默认有效期(天,0 = 不限)</span>
|
||||
<input type="number" name="default_validity_days" min="0" max="3650" value="{{.D.Package.DefaultValidityDays}}">
|
||||
</div>
|
||||
|
||||
<div class="grid-2">
|
||||
<label class="field" data-amount-wrap><span><span data-amount-title>默认量</span> <i>*</i></span>
|
||||
<label class="field" data-amount-wrap><span><span data-amount-title>默认天数</span> <i>*</i></span>
|
||||
<div class="input-suffix">
|
||||
<input type="number" name="default_amount" min="1" max="10000" value="{{.D.Package.DefaultAmount}}" required>
|
||||
<b data-unit-label>{{if eq .D.Package.Unit "count"}}次{{else}}天{{end}}</b>
|
||||
<b data-unit-label>天</b>
|
||||
</div>
|
||||
</label>
|
||||
<label class="field"><span>参考价(元,可空)</span>
|
||||
@@ -71,7 +41,7 @@
|
||||
|
||||
<label class="check-line">
|
||||
<input type="checkbox" name="calendar_separate" value="1"{{if .D.Package.CalendarSeparate}} checked{{end}}>
|
||||
<span>在日历中独立显示<small>通行证 / 深渊建议勾选:会单独开一个标签页,按色块连续展示,和其他日常任务分开看</small></span>
|
||||
<span>在日历中独立显示<small>勾选后会单独开一个标签页,和其他日常任务分开看</small></span>
|
||||
</label>
|
||||
|
||||
<label class="field"><span>说明</span>
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
{{define "content"}}
|
||||
<div class="portal-wrap">
|
||||
<header class="portal-head">
|
||||
<a class="portal-brand" href="/customer"><span class="brand-mark" aria-hidden="true">代</span><span>代打台</span></a>
|
||||
<h1>排单查询</h1>
|
||||
<p class="muted">输入手机尾号查看自己的排单与完成情况。</p>
|
||||
</header>
|
||||
|
||||
{{if .InlineError}}<div class="notice notice-danger portal-error" id="portal-error" role="alert">{{.InlineError}}</div>{{end}}
|
||||
|
||||
<details class="portal-search" {{if or (not .Query) .InlineError}}open{{end}}>
|
||||
<summary class="portal-search-head">{{if .InlineError}}修改查询{{else if .Query}}查询其他尾号{{else}}输入手机尾号查询{{end}}</summary>
|
||||
<form class="portal-form" method="get" action="/customer">
|
||||
<div class="portal-form-body">
|
||||
<div class="row g-2 align-items-end">
|
||||
<div class="col-12 col-sm-4">
|
||||
<label class="form-label" for="tail">手机尾号(4–8 位)</label>
|
||||
<input class="form-control" id="tail" name="tail" value="{{.Query}}" inputmode="numeric" pattern="[0-9]{4,8}" minlength="4" maxlength="8" placeholder="例如 2300" required{{if not .Query}} autofocus{{end}}{{if eq .InvalidField "tail"}} aria-invalid="true" aria-describedby="portal-error"{{end}}>
|
||||
</div>
|
||||
<div class="col-12 col-sm-4">
|
||||
<label class="form-label" for="name">客户姓名(可选)</label>
|
||||
<input class="form-control" id="name" name="name" value="{{.Name}}" maxlength="32" placeholder="尾号重复时填写"{{if eq .InvalidField "name"}} aria-invalid="true" aria-describedby="portal-error"{{end}}>
|
||||
</div>
|
||||
<div class="col-12 col-sm-4">
|
||||
<button class="btn btn-primary w-100" type="submit">查询</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="muted small mb-0 mt-2">只显示排单与完成情况,不含备注与价格。</p>
|
||||
</div>
|
||||
</form>
|
||||
</details>
|
||||
|
||||
{{with .D}}
|
||||
{{if .Masked}}
|
||||
<section class="portal-result">
|
||||
<div class="card mt-3"><div class="card-body">
|
||||
<h2 class="h5">找到 {{.Count}} 位客户</h2>
|
||||
<p class="muted mb-2">尾号 {{.Tail}} 对应多位客户,请补一个姓名后查询。</p>
|
||||
{{if .Masked}}<p class="portal-ask-names">可能是:{{range $i, $n := .Masked}}{{if $i}}、{{end}}{{$n}}{{end}}</p>{{end}}
|
||||
<form class="portal-ask-form" method="get" action="/customer">
|
||||
<input type="hidden" name="tail" value="{{.Tail}}">
|
||||
<label class="visually-hidden" for="ask-name">姓名</label>
|
||||
<input class="form-control" id="ask-name" name="name" maxlength="32" placeholder="输入姓名(可只填一部分)" required autofocus>
|
||||
<button class="btn btn-primary" type="submit">查询</button>
|
||||
</form>
|
||||
</div></div>
|
||||
</section>
|
||||
{{else}}
|
||||
<section class="portal-result">
|
||||
{{if .Subs}}
|
||||
<div class="card mt-3"><div class="card-body">
|
||||
<div class="portal-client">
|
||||
<div class="portal-client-main">
|
||||
<h2 class="portal-client-name">{{.Tail}} · {{.Name}}</h2>
|
||||
<div class="portal-client-meta">
|
||||
{{if .Game}}<span class="tagchip">{{.Game}}</span>{{end}}
|
||||
{{if .Expiring}}<span class="tagchip">最近到期 {{.Expiring}}</span>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="portal-client-status">
|
||||
{{if eq .TodayState "done"}}<span class="chip chip-active">今日已清完</span>
|
||||
{{else if eq .TodayState "pending"}}<span class="chip chip-plain">今日待完成 {{.TodayPending}} / {{.TodayTotal}}</span>
|
||||
{{else}}<span class="chip chip-plain">今日无排单</span>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
<div class="card mt-3"><div class="card-body">
|
||||
<div class="portal-section-head"><h2>订阅</h2><span class="portal-section-count">{{.SubCount}}</span></div>
|
||||
<div class="portal-sub-list">
|
||||
{{range .Subs}}
|
||||
<article class="portal-sub">
|
||||
<div class="portal-sub-main">
|
||||
<strong>{{.PackageName}}</strong>
|
||||
<span class="tagchip">{{.UnitLabel}}</span>
|
||||
{{if .TodayLabel}}<span class="chip chip-{{.TodayClass}}">{{.TodayLabel}}</span>{{else}}{{template "state-chip" .}}{{end}}
|
||||
</div>
|
||||
<div class="portal-sub-meta">
|
||||
<span>{{.RemainText}}</span>
|
||||
<span class="muted">{{.PeriodText}}</span>
|
||||
</div>
|
||||
</article>
|
||||
{{end}}
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
<div class="card mt-3"><div class="card-body">
|
||||
<div class="portal-section-head">
|
||||
<h2>当月排单</h2>
|
||||
<div class="pcal-nav">
|
||||
<a class="btn btn-soft pcal-nav-btn" href="{{.Prev}}" aria-label="上个月">‹</a>
|
||||
<b>{{.MonthTitle}}</b>
|
||||
<a class="btn btn-soft pcal-nav-btn" href="{{.Next}}" aria-label="下个月">›</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pcal" role="grid" aria-label="{{.MonthTitle}}排单">
|
||||
<div class="pcal-dow" role="row">
|
||||
<span role="columnheader">一</span><span role="columnheader">二</span><span role="columnheader">三</span><span role="columnheader">四</span><span role="columnheader">五</span><span role="columnheader">六</span><span role="columnheader">日</span>
|
||||
</div>
|
||||
{{range .Weeks}}
|
||||
<div class="pcal-row" role="row">
|
||||
{{range .}}
|
||||
<div class="pcal-cell{{if not .InMonth}} out{{end}}{{if .Today}} today{{end}}{{if .BlockColor}} has-block{{end}}" role="gridcell" aria-label="{{.Label}}"{{if .BlockColor}} style="--block:{{.BlockColor}};--block-pct:{{.BlockPercent}}%"{{end}}>
|
||||
<b>{{.Day}}</b>
|
||||
{{if .Today}}<i class="pcal-today">今天</i>{{end}}
|
||||
{{if .BlockText}}<span class="pcal-block" title="{{.BlockTitle}}">{{.BlockText}}</span>{{end}}
|
||||
{{if .Total}}{{if eq .Total 1}}<span class="pcal-dot{{if .Done}} done{{end}}" title="{{.Done}}/{{.Total}} 单"></span>{{else}}<span class="pcal-count">{{.Done}}/{{.Total}}</span>{{end}}{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div></div>
|
||||
{{else}}
|
||||
<div class="card mt-3"><div class="card-body">
|
||||
<h2 class="h4 mb-1">{{.Tail}} · {{.Name}}</h2>
|
||||
<div class="portal-client-meta">{{if .Game}}<span class="tagchip">{{.Game}}</span>{{end}}</div>
|
||||
<p class="muted mb-0 mt-3">还没有进行中的订阅。如需开通,请联系你的代打。</p>
|
||||
</div></div>
|
||||
{{end}}
|
||||
</section>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -1,157 +0,0 @@
|
||||
{{define "content"}}
|
||||
<div class="scr" data-pkg="{{.D.PkgID}}" data-heat="{{.D.HeatMode}}" data-api="/api/screen/day">
|
||||
<header class="scr-head">
|
||||
<div class="scr-brand"><span class="mark" aria-hidden="true">代</span>代打台<em>控制台</em></div>
|
||||
|
||||
{{if .D.HasTabs}}
|
||||
<nav class="scr-tabs">
|
||||
{{range .D.Tabs}}
|
||||
<a class="{{if .Active}}on{{end}}" style="--tab:{{.Color}}" href="{{.Href}}">{{.Name}}</a>
|
||||
{{end}}
|
||||
</nav>
|
||||
{{end}}
|
||||
|
||||
<div class="scr-tools">
|
||||
<a class="scr-switch" href="/screen?{{.D.FilterQuery}}&heat={{if eq .D.HeatMode "due"}}task{{else}}due{{end}}"
|
||||
title="切换热力统计口径">
|
||||
{{if eq .D.HeatMode "due"}}热力:到期{{else}}热力:待完成{{end}} ⇄
|
||||
</a>
|
||||
<button class="scr-theme" type="button" data-theme-toggle aria-label="切换亮色/暗色" aria-pressed="false">
|
||||
<span class="ic-moon" aria-hidden="true">☾</span><span class="ic-sun" aria-hidden="true">☀</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="scr-clock"><b data-clock>--:--:--</b><span data-date></span></div>
|
||||
<div class="scr-links">每 {{.D.Refresh}} 秒刷新 · <a href="/calendar">进入工作台</a></div>
|
||||
</header>
|
||||
|
||||
<section class="scr-kpis">
|
||||
<div class="kpi">
|
||||
<span>客户</span><b>{{.D.Stats.Customers}}</b><i>位</i>
|
||||
</div>
|
||||
<div class="kpi">
|
||||
<span>活跃订阅</span><b>{{.D.Stats.ActiveSubs}}</b><i>条</i>
|
||||
</div>
|
||||
<div class="kpi kpi-hot">
|
||||
<span>今日到期</span><b>{{.D.Stats.DueToday}}</b><i>条</i>
|
||||
</div>
|
||||
<div class="kpi kpi-warm">
|
||||
<span>7 天内到期</span><b>{{.D.Stats.Due7}}</b><i>条</i>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="scr-main">
|
||||
<div class="panel panel-cal">
|
||||
<div class="panel-head">
|
||||
<h2>{{if eq .D.HeatMode "due"}}到期热力{{else}}每日待完成{{end}}</h2>
|
||||
<span>{{.D.MonthTitle}} · 本月合计 {{.D.HeatTotal}} 单</span>
|
||||
</div>
|
||||
<div class="heat-grid">
|
||||
<div class="heat-dow">{{range .D.Weekdays}}<span>{{.}}</span>{{end}}</div>
|
||||
{{range .D.Weeks}}
|
||||
<div class="heat-row">
|
||||
{{range .}}
|
||||
<div class="heat-cell h{{.Heat}}{{if not .InMonth}} out{{end}}{{if .IsToday}} today{{end}}{{if .IsPast}} past{{end}}{{if .BlockColor}} has-block{{end}}"
|
||||
data-date="{{.Date}}" title="{{if .BlockTitle}}{{.BlockTitle}} · {{end}}{{.Date}}"{{if .BlockColor}} style="--block:{{.BlockColor}};--block-pct:{{.BlockPercent}}%"{{end}}>
|
||||
{{if .Strip}}<span class="asg-strip sm" aria-hidden="true">{{range .Strip}}<i style="background:{{.}}"></i>{{end}}</span>{{end}}
|
||||
<span>{{.Day}}</span>
|
||||
{{if gt .Urgent 0}}<u class="cell-urgent"></u>{{end}}
|
||||
{{if and .BlockText (not .Count)}}<b class="scr-block">{{.BlockText}}</b>{{else if .Count}}<b>{{.Done}}/{{.Count}}</b>{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="heat-legend">
|
||||
<span>{{if eq .D.HeatMode "due"}}到期数{{else}}待完成单量{{end}}</span>
|
||||
<i class="h0"></i><i class="h1"></i><i class="h2"></i><i class="h3"></i><i class="h4"></i>
|
||||
<em class="legend-hint">悬停格子看当日明细</em>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-top">
|
||||
<div class="panel-head"><h2>即将到期 TOP 10</h2><span>按剩余量排序</span></div>
|
||||
{{if .D.Top}}
|
||||
<ol class="top-list">
|
||||
{{range $i, $s := .D.Top}}
|
||||
<li class="top-item lv-{{$s.Eval.Level}}">
|
||||
<span class="rank">{{add $i 1}}</span>
|
||||
<span class="top-tail">{{$s.CustomerTail}}</span>
|
||||
<span class="top-name">{{$s.CustomerName}}</span>
|
||||
<span class="top-pkg" style="--tag:{{$s.PackageColor}}">{{$s.PackageName}}</span>
|
||||
<span class="top-remain">{{$s.RemainShort}}</span>
|
||||
<span class="top-bar"><i style="width:{{$s.Progress}}%"></i></span>
|
||||
</li>
|
||||
{{end}}
|
||||
</ol>
|
||||
{{else}}
|
||||
<p class="scr-empty">暂无订阅数据</p>
|
||||
{{end}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="scr-bottom">
|
||||
<div class="panel">
|
||||
<div class="panel-head">
|
||||
<h2>今日到期</h2>
|
||||
<span>{{len .D.DueToday}} 条</span>
|
||||
</div>
|
||||
{{if .D.DueToday}}
|
||||
<ul class="today-list">
|
||||
{{range .D.DueToday}}
|
||||
<li class="lv-{{.Eval.Level}}">
|
||||
<span class="tchip" style="--tag:{{.PackageColor}}"><b>{{.CustomerTail}}</b>{{.CustomerName}}</span>
|
||||
<span class="pkg">{{.PackageName}}</span>
|
||||
<span class="rem">{{.RemainShort}}</span>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p class="scr-empty">今天没有到期</p>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-head">
|
||||
<h2>今日待打</h2>
|
||||
<span>{{.D.TodayDone}} / {{.D.TodayTasks}} 已完成{{if gt .D.TodayUrgent 0}} · 加急 {{.D.TodayUrgent}}{{end}}</span>
|
||||
</div>
|
||||
{{if .D.TodayList}}
|
||||
<ul class="today-list">
|
||||
{{range .D.TodayList}}
|
||||
<li class="{{if .Urgent}}urgent {{end}}lv-{{.Eval.Level}}">
|
||||
<span class="tchip" style="--tag:{{.PackageColor}}"><b>{{.CustomerTail}}</b>{{.CustomerName}}</span>
|
||||
<span class="pkg">{{.PackageName}}</span>
|
||||
<span class="asg{{if .AssigneeNone}} none{{end}}"><i style="background:{{.AssigneeHex}}"></i>{{.AssigneeLabel}}</span>
|
||||
{{if .Urgent}}<span class="tag-urgent">加急</span>{{end}}
|
||||
<span class="rem">{{.RemainShort}}</span>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p class="scr-empty">今天没有待打任务</p>
|
||||
{{end}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="scr-recent">
|
||||
<span class="recent-label">最近追加</span>
|
||||
{{if .D.Recent}}
|
||||
<div class="recent-track">
|
||||
{{range .D.Recent}}
|
||||
<span class="recent-item"><b>{{.CustomerTail}}</b>{{.CustomerName}} · {{.PackageName}}
|
||||
{{if gt .DaysAdded 0}}<em>+{{.DaysAdded}} 天</em>{{end}}
|
||||
{{if gt .CountAdded 0}}<em>+{{.CountAdded}} 次</em>{{end}}
|
||||
</span>
|
||||
{{end}}
|
||||
</div>
|
||||
{{else}}
|
||||
<span class="scr-empty-inline">还没有追加记录</span>
|
||||
{{end}}
|
||||
</section>
|
||||
|
||||
<footer class="scr-foot">代打台 v{{.D.Version}} · 数据每 {{.D.Refresh}} 秒自动刷新 · 按 F 全屏</footer>
|
||||
|
||||
<div class="day-pop" id="day-pop" hidden></div>
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -3,73 +3,21 @@
|
||||
<header class="page-head">
|
||||
<div>
|
||||
<h1>设置</h1>
|
||||
<p>预警天数、备份、账户与数据导出</p>
|
||||
<p>预警天数、备份与数据导出</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="section card">
|
||||
<h2>基础设置</h2>
|
||||
<form method="post" action="/settings" class="form">
|
||||
<div class="grid-2">
|
||||
<label class="field"><span>到期预警(天)</span>
|
||||
<input type="number" name="warn_days" min="0" max="60" value="{{.D.WarnDays}}">
|
||||
</label>
|
||||
<label class="field"><span>大屏自动刷新(秒)</span>
|
||||
<input type="number" name="screen_refresh" min="5" max="600" value="{{.D.ScreenRefresh}}">
|
||||
</label>
|
||||
</div>
|
||||
<label class="field field-narrow"><span>到期预警(天)</span>
|
||||
<input type="number" name="warn_days" min="0" max="60" value="{{.D.WarnDays}}">
|
||||
</label>
|
||||
<p class="muted small">监听地址、端口、数据库、备份、日志、时区等部署参数在 <code>daili.ini</code> 里配置,改完重启生效。</p>
|
||||
<div class="actions"><button class="btn btn-primary" type="submit">保存设置</button></div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="section card">
|
||||
<h2>管理员</h2>
|
||||
<p class="muted small">所有账户权限相同,任何操作都会记在日志里。每个管理员的颜色用于日历左侧竖条和待办标识。</p>
|
||||
<p class="muted small">{{if eq .User.ID 1}}你是初始管理员,可以点「编辑」修改其他管理员的用户名、昵称和密码。{{else}}只有初始管理员(首个账号)可以修改其他管理员的资料。{{end}}</p>
|
||||
<div class="table-wrap">
|
||||
<table class="table tight table-users">
|
||||
<thead><tr><th scope="col">用户名</th><th scope="col">显示名称</th><th scope="col">打手颜色</th><th scope="col">状态</th><th scope="col">创建时间</th><th scope="col">最近登录</th><th scope="col"><span class="visually-hidden">操作</span></th></tr></thead>
|
||||
<tbody>
|
||||
{{$me := .User}}
|
||||
{{range .D.Users}}
|
||||
<tr>
|
||||
<td class="mono">{{.Username}}</td>
|
||||
<td>{{.DisplayName}}</td>
|
||||
<td>
|
||||
<form method="post" action="/settings/users/{{.ID}}/color" class="color-form">
|
||||
<input type="color" name="color" value="{{if .Color}}{{.Color}}{{else}}#8A8F98{{end}}" title="打手颜色" aria-label="打手颜色">
|
||||
<button class="btn btn-soft btn-sm" type="submit">保存</button>
|
||||
</form>
|
||||
</td>
|
||||
<td>{{if .IsActive}}<span class="chip chip-active">启用</span>{{else}}<span class="chip chip-closed">停用</span>{{end}}</td>
|
||||
<td class="mono small">{{.CreatedAt}}</td>
|
||||
<td class="mono small">{{if .LastLoginAt}}{{.LastLoginAt}}{{else}}—{{end}}</td>
|
||||
<td class="actions-cell">
|
||||
{{if eq .ID $me.ID}}
|
||||
<span class="muted small">当前账户</span>
|
||||
{{else}}
|
||||
{{if eq $me.ID 1}}
|
||||
<a class="btn btn-soft btn-sm" href="/settings/users/{{.ID}}/edit">编辑</a>
|
||||
{{end}}
|
||||
<form method="post" action="/settings/users/{{.ID}}/toggle">
|
||||
<button class="btn btn-ghost btn-sm">{{if .IsActive}}停用{{else}}启用{{end}}</button>
|
||||
</form>
|
||||
{{end}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<form method="post" action="/settings/users" class="inline-form">
|
||||
<label class="inline-field">用户名 <input type="text" name="username" required minlength="3" maxlength="32" autocomplete="off"></label>
|
||||
<label class="inline-field">显示名称 <input type="text" name="display_name" maxlength="32"></label>
|
||||
<label class="inline-field">初始密码 <input type="password" name="password" required minlength="6" autocomplete="new-password"></label>
|
||||
<button class="btn btn-primary" type="submit">新增管理员</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="section card">
|
||||
<h2>修改我的密码</h2>
|
||||
<form method="post" action="/settings/password" class="form">
|
||||
@@ -88,9 +36,7 @@
|
||||
<div><dt>配置文件</dt><dd class="mono small">{{.D.ConfigPath}} <span class="muted">(修改后重启生效)</span></dd></div>
|
||||
<div><dt>数据库</dt><dd class="mono small">{{.D.DBPath}}</dd></div>
|
||||
<div><dt>备份</dt><dd class="mono small">{{.D.BackupDir}} · 保留 {{.D.BackupKeep}} 份 · {{if .D.BackupEnabled}}自动备份已开启{{else}}自动备份已关闭{{end}}</dd></div>
|
||||
<div><dt>大屏</dt><dd class="mono small">/screen {{if .D.ScreenPublic}}免登录{{else}}需登录{{end}}</dd></div>
|
||||
<div><dt>客户自助</dt><dd class="mono small">/customer {{if .D.PortalPublic}}免登录{{else}}已关闭{{end}}</dd></div>
|
||||
<div><dt>局域网地址</dt><dd class="mono small">http://{{if .D.Addrs}}{{index .D.Addrs 0}}{{else}}127.0.0.1{{end}}:{{.D.Port}}/screen</dd></div>
|
||||
<div><dt>局域网地址</dt><dd class="mono small">http://{{if .D.Addrs}}{{index .D.Addrs 0}}{{else}}127.0.0.1{{end}}:{{.D.Port}}</dd></div>
|
||||
<div><dt>已运行</dt><dd class="mono">{{.D.Uptime}}</dd></div>
|
||||
<div><dt>数据量</dt><dd>{{.D.CustomerCount}} 位客户 · {{.D.PackageCount}} 个套餐 · {{.D.LogCount}} 条日志</dd></div>
|
||||
</dl>
|
||||
|
||||
@@ -2,17 +2,16 @@
|
||||
<div class="auth">
|
||||
<button class="theme-toggle auth-theme" type="button" data-theme-toggle aria-label="切换亮色/暗色" aria-pressed="false"><span class="ic-moon" aria-hidden="true">☾</span><span class="ic-sun" aria-hidden="true">☀</span></button>
|
||||
<div class="auth-card">
|
||||
<div class="auth-brand"><span class="brand-mark" aria-hidden="true">代</span><span>代打台</span></div>
|
||||
<h1>创建第一个管理员</h1>
|
||||
<p>数据库里还没有账户。设置好账号后即可开始录入套餐与客户。</p>
|
||||
<div class="auth-brand"><span class="brand-mark" aria-hidden="true">代</span><span>代打台-L</span></div>
|
||||
<h1>创建管理员</h1>
|
||||
<p>数据库里还没有账户。创建后不能再添加其他管理员。</p>
|
||||
<form method="post" action="/setup" class="stack">
|
||||
<label class="field"><span>用户名</span>
|
||||
<input class="form-control" id="username" type="text" name="username" required minlength="3" maxlength="32" autocomplete="username" placeholder="建议用拼音或英文名">
|
||||
</label>
|
||||
<label class="field"><span>显示名称</span>
|
||||
<input class="form-control" id="display_name" type="text" name="display_name" maxlength="32" placeholder="例如:老王(可留空)">
|
||||
</label>
|
||||
<label class="field"><span>密码(至少 6 位)</span>
|
||||
</label> <label class="field"><span>密码(至少 6 位)</span>
|
||||
<input class="form-control" id="password" type="password" name="password" required minlength="6" autocomplete="new-password">
|
||||
</label>
|
||||
<label class="field"><span>再输一次密码</span>
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<td class="mono small">{{.PeriodText}}</td>
|
||||
<td class="actions-cell">
|
||||
{{if ne .Status "closed"}}
|
||||
{{if not (or .Season .Abyss)}}<a class="btn btn-soft btn-sm" href="/customers/{{.CustomerID}}?extend={{.ID}}#extend">追加</a>{{end}}
|
||||
<a class="btn btn-soft btn-sm" href="/customers/{{.CustomerID}}?extend={{.ID}}#extend">追加</a>
|
||||
{{if eq .Status "active"}}
|
||||
<form method="post" action="/subscriptions/{{.ID}}/pause"><button class="btn btn-ghost btn-sm">暂停</button></form>
|
||||
{{else if eq .Status "paused"}}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
{{define "content"}}
|
||||
<div class="page narrow">
|
||||
<header class="page-head">
|
||||
<div>
|
||||
<h1>编辑管理员</h1>
|
||||
<p class="muted">修改 {{.D.Target.Username}} 的登录名、昵称,或重置密码。</p>
|
||||
</div>
|
||||
<div class="page-actions">
|
||||
<a class="btn btn-ghost" href="/settings">返回设置</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<form method="post" action="/settings/users/{{.D.Target.ID}}/edit" class="form card">
|
||||
<div class="grid-2">
|
||||
<label class="field"><span>用户名 <i>*</i></span>
|
||||
<input type="text" name="username" value="{{.D.Target.Username}}" required minlength="3" maxlength="32" autocomplete="off">
|
||||
</label>
|
||||
<label class="field"><span>显示名称</span>
|
||||
<input type="text" name="display_name" value="{{.D.Target.DisplayName}}" maxlength="32" autocomplete="off">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="grid-2">
|
||||
<label class="field"><span>新密码</span>
|
||||
<input type="password" name="password" minlength="6" autocomplete="new-password" placeholder="留空则不修改">
|
||||
</label>
|
||||
<label class="field"><span>再输一次</span>
|
||||
<input type="password" name="password2" minlength="6" autocomplete="new-password" placeholder="与上面一致">
|
||||
</label>
|
||||
</div>
|
||||
<p class="muted small">重置密码后该账户的登录会话会立即失效,需要用新密码重新登录。当前账户:{{.User.Username}}</p>
|
||||
|
||||
<div class="actions">
|
||||
<button class="btn btn-primary" type="submit">保存修改</button>
|
||||
<a class="btn btn-ghost" href="/settings">取消</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
||||
Reference in New Issue
Block a user