feat: 新增短链接工具,优化日历提醒功能

1. 新增完整短链接工具服务,包括前端页面、后端API与数据库支持
2. 新增移动端日历提醒工具与鉴权配置
3. 优化日历事件编辑与展示:
   - 添加事件循环重复设置
   - 新增全天事件支持
   - 时间选择器自动对齐15分钟间隔
   - 保存状态加载动画
   - 事件卡片显示重复规则
4. 更新API基础地址与路由配置
5. 新增SSL证书文件与相关工具静态资源
This commit is contained in:
yangxiangyuan
2026-07-28 16:23:37 +08:00
parent 212dbc4e1d
commit 154b79c8f1
18 changed files with 3508 additions and 23 deletions
+170
View File
@@ -0,0 +1,170 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Yang's Toolbox · 短链接</title>
<link rel="icon" href="/assets/picker.svg" type="image/svg+xml" />
<link rel="stylesheet" href="/common/common.css" />
<link rel="stylesheet" href="/tools/short_link/short_link.css" />
</head>
<body>
<div class="topbar">
<div class="tabs">
<a class="tab" href="/">首页</a>
<a class="tab active" href="/tools/short_link/index.html">短链接</a>
</div>
<div class="topbar-right">
<span id="mode-badge" class="mode-badge">debug</span>
</div>
</div>
<main>
<!-- 创建区域 -->
<section class="card create-card">
<h2>创建短链接</h2>
<div class="form-grid">
<div class="form-row full">
<label for="inp-url">目标链接 <span class="req">*</span></label>
<input id="inp-url" type="url" placeholder="https://example.com/very/long/path?with=params" />
</div>
<div class="form-row">
<label for="inp-title">备注标题</label>
<input id="inp-title" type="text" placeholder="可选,方便识别" />
</div>
<div class="form-row">
<label for="inp-code">自定义短码</label>
<input id="inp-code" type="text" placeholder="留空则自动生成" maxlength="20" />
</div>
<div class="form-row">
<label for="inp-expires">过期时间</label>
<input id="inp-expires" type="datetime-local" />
</div>
<div class="form-row">
<label for="inp-maxclicks">最大点击数</label>
<input id="inp-maxclicks" type="number" min="0" placeholder="不限" />
</div>
</div>
<div class="form-actions">
<button id="btn-create" class="btn btn-primary">生成短链接</button>
</div>
</section>
<!-- 工具别名区域 -->
<section class="card alias-card">
<h2>工具快捷入口</h2>
<p class="hint">以下别名在 config/short_link.json 中配置,访问对应短链接可直接跳转到工具</p>
<div id="alias-list" class="alias-grid"></div>
</section>
<!-- 列表区域 -->
<section class="card list-card">
<div class="list-header">
<h2>短链接列表</h2>
<div class="list-toolbar">
<input id="inp-search" type="text" placeholder="搜索短码/链接/标题…" />
<button id="btn-search" class="btn btn-sm">搜索</button>
<button id="btn-refresh" class="btn btn-sm">刷新</button>
</div>
</div>
<div class="table-wrap">
<table id="link-table">
<thead>
<tr>
<th>短链接</th>
<th>目标</th>
<th>备注</th>
<th>点击</th>
<th>创建时间</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody id="link-tbody"></tbody>
</table>
</div>
<div id="pagination" class="pagination"></div>
</section>
</main>
<!-- 交互详情弹窗 -->
<div class="modal hidden" id="interaction-modal">
<div class="modal-body interaction-modal-body">
<h3 id="interaction-title">交互详情</h3>
<div id="interaction-content" class="interaction-content"></div>
<div class="modal-actions">
<button id="btn-interaction-copy" class="btn btn-sm">复制日志</button>
<button id="btn-interaction-close" class="btn btn-sm">关闭</button>
<span id="interaction-countdown" class="countdown"></span>
</div>
</div>
</div>
<!-- 确认弹窗 -->
<div class="modal hidden" id="confirm-modal">
<div class="modal-body confirm-modal-body">
<h3 id="confirm-title">确认操作</h3>
<p id="confirm-message"></p>
<div class="modal-actions">
<button id="btn-confirm-yes" class="btn btn-danger btn-sm">确认</button>
<button id="btn-confirm-no" class="btn btn-sm">取消</button>
</div>
</div>
</div>
<!-- 编辑弹窗 -->
<div class="modal hidden" id="edit-modal">
<div class="modal-body edit-modal-body">
<h3>编辑短链接</h3>
<input type="hidden" id="edit-code" />
<div class="form-grid">
<div class="form-row full">
<label for="edit-url">目标链接</label>
<input id="edit-url" type="url" />
</div>
<div class="form-row">
<label for="edit-title">备注标题</label>
<input id="edit-title" type="text" />
</div>
<div class="form-row">
<label for="edit-expires">过期时间</label>
<input id="edit-expires" type="datetime-local" />
</div>
<div class="form-row">
<label for="edit-maxclicks">最大点击数</label>
<input id="edit-maxclicks" type="number" min="0" />
</div>
<div class="form-row">
<label for="edit-active">状态</label>
<select id="edit-active">
<option value="1">启用</option>
<option value="0">停用</option>
</select>
</div>
</div>
<div class="modal-actions">
<button id="btn-edit-save" class="btn btn-primary btn-sm">保存</button>
<button id="btn-edit-cancel" class="btn btn-sm">取消</button>
</div>
</div>
</div>
<!-- 统计弹窗 -->
<div class="modal hidden" id="stats-modal">
<div class="modal-body stats-modal-body">
<h3 id="stats-title">点击统计</h3>
<div id="stats-summary" class="stats-summary"></div>
<div id="stats-clicks" class="stats-clicks"></div>
<div class="modal-actions">
<button id="btn-stats-close" class="btn btn-sm">关闭</button>
</div>
</div>
</div>
<!-- Toast -->
<div id="toast" class="toast hidden"></div>
<script src="/common/common.js"></script>
<script src="/tools/short_link/short_link.js"></script>
</body>
</html>