Files
Aq-Accounting-Spring/src/main/resources/static/admin/index.html
T
2026-09-28 17:16:41 +08:00

389 lines
17 KiB
HTML
Raw 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.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>强宝小助手</title>
<link rel="stylesheet" href="/admin/vendor/vditor/dist/index.css">
<link rel="stylesheet" href="/admin/admin.css">
</head>
<body>
<!-- ==================== 登录 ====================
视觉对齐手机端登录页:暖橙渐变底 + 漂浮圆球 + 圆形熊头 + 金色装饰线标题
+ 毛玻璃卡片 + emoji 前缀输入框。改这里之前先看 App 的 login_page.dart。
-->
<div id="login-view">
<!-- 背景装饰圆球(手机端是带缓动的,这里用 CSS 动画近似) -->
<div class="login-balls" aria-hidden="true">
<span class="ball b1"></span>
<span class="ball b2"></span>
<span class="ball b3"></span>
</div>
<div class="login-wrap">
<div class="login-header">
<div class="login-logo">
<img src="/admin/logo.png" alt="强宝小助手">
</div>
<h1 class="login-title">
<i class="deco"></i><span>强宝小助手</span><i class="deco"></i>
</h1>
<p class="login-sub">智能记账,轻松管理</p>
</div>
<div class="login-box">
<div class="login-field">
<span class="ico"><img class="ci" src="/admin/icons/user.svg" width="18" height="18" alt=""></span>
<input id="login-username" autocomplete="username" maxlength="20" placeholder="请输入用户名">
</div>
<div class="login-field">
<span class="ico"><img class="ci" src="/admin/icons/lock.svg" width="18" height="18" alt=""></span>
<input id="login-password" type="password" autocomplete="current-password" maxlength="20"
placeholder="请输入密码">
<button type="button" class="eye" id="login-eye" title="显示密码">
<img class="ci" src="/admin/icons/eye.svg" width="18" height="18" alt="">
</button>
</div>
<button class="login-btn" id="login-btn">登 录</button>
</div>
</div>
</div>
<!-- ==================== 主界面 ====================
三层结构:
顶栏 —— 系统级,只放品牌和用户操作(跨模块的东西才配放这儿)
模块菜单 —— 左侧,以后加 Agent 等模块直接往这里塞
模块面板 —— 当前模块自己的工具栏、侧栏和内容
-->
<div id="app-view" style="display:none">
<header class="topbar">
<div class="brand"><img class="brand-logo" src="/admin/logo.png" alt="">强宝小助手</div>
<div class="spacer"></div>
<span class="who" id="who"></span>
<button id="logout-btn">退出</button>
</header>
<div class="console">
<nav class="module-nav">
<button class="module-item active" data-module="notes">
<span class="mi-icon"><img class="ci" src="/admin/icons/note.svg" width="18" height="18" alt=""></span>
<span class="mi-text">笔记管理</span>
</button>
<button class="module-item" data-module="finance">
<span class="mi-icon"><img class="ci" src="/admin/icons/bill.svg" width="18" height="18" alt=""></span>
<span class="mi-text">财务管理</span>
</button>
<button class="module-item" data-module="photos">
<span class="mi-icon"><img class="ci" src="/admin/icons/camera.svg" width="18" height="18" alt=""></span>
<span class="mi-text">相片管理</span>
</button>
<button class="module-item" data-module="ai">
<span class="mi-icon"><img class="ci" src="/admin/icons/assistant.svg" width="18" height="18"
alt=""></span>
<span class="mi-text">AI 助手</span>
</button>
<!-- 以后的模块(数据看板…)往这里加:这里加一个 button,
下面加一个 data-module-panel 的 section,再在 admin.js 的
switchModule 里按需做初始化就行 -->
</nav>
<section class="module-panel" data-module-panel="notes">
<div class="toolbar">
<input id="search" placeholder="搜索标题和正文…">
<select id="scope" title="搜索范围">
<option value="current" selected>当前目录</option>
<option value="all">全部笔记</option>
</select>
<select id="sort" title="排序方式">
<option value="updated">最近更新</option>
<option value="created">创建时间</option>
<option value="title">标题</option>
</select>
<div class="spacer"></div>
<button id="new-folder-btn">+ 新建目录</button>
<button id="new-btn" class="primary">+ 新建笔记</button>
</div>
<div class="module-body">
<aside class="sidebar">
<div id="folder-tree"></div>
<div class="side-divider"></div>
<div class="side-title">标签</div>
<div id="tag-list"></div>
</aside>
<main class="content">
<div class="breadcrumb" id="breadcrumb"></div>
<div id="dropzone">
把 <b>.md</b> 文件拖到这里批量导入<span id="dropzone-hint"></span>,或 <a href="#"
id="pick-files">点击选择文件</a>
<input type="file" id="file-input" accept=".md,.markdown,.txt" multiple style="display:none">
</div>
<div id="note-list"></div>
<button id="loadmore" style="display:none">加载更多</button>
</main>
</div>
</section>
<!-- ==================== 财务管理模块 ====================
纯展示:月度汇总 / 预算进度 / 分类占比 / 账单明细。
记账和改账在 App 上做,这里只读 —— 数据全部来自现成接口
(/statistics/monthly、/bills、/budget、/account)。 -->
<section class="module-panel" data-module-panel="finance" style="display:none">
<div class="toolbar">
<button class="icon-btn" id="fin-prev" title="上一月">‹</button>
<span class="fin-month" id="fin-month">—</span>
<button class="icon-btn" id="fin-next" title="下一月">›</button>
<div class="toolbar-sep"></div>
<select id="fin-type" title="按类型筛选">
<option value="">全部类型</option>
<option value="1">只看支出</option>
<option value="2">只看收入</option>
</select>
<select id="fin-cat" title="按分类筛选">
<option value="">全部分类</option>
</select>
<div class="spacer"></div>
<span class="toolbar-note" id="fin-note"></span>
</div>
<div class="module-body">
<aside class="sidebar">
<div class="side-title">本月概览</div>
<div id="fin-summary"></div>
<div class="side-divider"></div>
<div class="side-title">分类(点一下筛选)</div>
<div id="fin-cats"></div>
</aside>
<main class="content">
<div id="fin-bills"></div>
</main>
</div>
</section>
<!-- ==================== AI 助手模块 ====================
和 App 端共用同一套后端接口(/api/ai/**),历史存在服务端的
chat_session / chat_message 里 —— 所以两边看到的会话是同一批。 -->
<!-- ==================== 相片管理 ==================== -->
<section class="module-panel" data-module-panel="photos" style="display:none">
<div class="toolbar">
<span class="toolbar-title">相片管理</span>
<span class="toolbar-note" id="photo-hint"></span>
<div class="spacer"></div>
<button id="photo-reload">刷新</button>
</div>
<div class="module-body">
<main class="photo-main">
<!-- 缩略图网格。点一张看大图,右上角可下载/删除 -->
<div id="photo-grid" class="photo-grid"></div>
<div id="photo-more" class="photo-more" style="display:none">
<button id="photo-more-btn">加载更多</button>
</div>
</main>
</div>
</section>
<section class="module-panel" data-module-panel="ai" style="display:none">
<div class="toolbar">
<span class="toolbar-title">AI 助手</span>
<!-- 当前用哪个模型。放在工具栏上让「切错了模型」一眼可见 -->
<select id="ai-config-select" title="切换模型配置"></select>
<span class="toolbar-note" id="ai-hint"></span>
<div class="spacer"></div>
<button id="ai-persona-manage">配置人设…</button>
<button id="ai-config-manage">配置模型…</button>
<button id="ai-new">+ 新对话</button>
</div>
<div class="module-body">
<aside class="sidebar">
<div class="side-title">历史对话</div>
<div id="ai-session-list"></div>
</aside>
<main class="ai-main">
<div id="ai-messages" class="ai-messages"></div>
<!-- 工具调用提示(「正在查账单…」),没有在查东西时整行隐藏 -->
<div class="ai-status" id="ai-status" style="display:none"></div>
<div class="ai-composer">
<textarea id="ai-input" rows="1"
placeholder="问点什么,或者说一句…(Enter 发送,Shift+Enter 换行)"></textarea>
<button class="primary" id="ai-send">发送</button>
</div>
</main>
</div>
</section>
</div>
</div>
<!-- ==================== 编辑器 ==================== -->
<div id="editor">
<div class="editor-box">
<div class="editor-head">
<input class="title" id="ed-title" placeholder="标题(留空则自动取正文首行)">
<input class="tags" id="ed-tags" placeholder="标签,逗号分隔">
</div>
<div class="editor-body">
<div id="vditor"></div>
</div>
<div class="editor-foot">
<span class="hint" id="ed-hint"></span>
<button id="ed-cancel">取消</button>
<button class="primary" id="ed-save">保存 (Ctrl+S)</button>
</div>
</div>
</div>
<!-- ==================== AI 模型配置 ==================== -->
<div id="ai-cfg">
<div class="cfg-box">
<div class="cfg-head">
<h3>AI 模型配置</h3>
<div class="spacer"></div>
<button class="primary" id="cfg-add">+ 新增</button>
<button id="cfg-close">关闭</button>
</div>
<p class="cfg-tip">
「默认」用的是服务器 <code>.env</code> 里那套,不能在这里改。
下面配的几条会存到你自己的账号下,手机端也能看到并切换。
</p>
<div id="cfg-list" class="cfg-list"></div>
</div>
</div>
<!-- ==================== 新增/编辑单条配置 ==================== -->
<div id="cfg-edit">
<div class="dialog-box cfg-edit-box">
<h3 id="cfg-edit-title">新增配置</h3>
<label class="cfg-field">
<span>名称</span>
<input id="cfg-f-name" placeholder="留空则用模型名,比如:DeepSeek 便宜">
</label>
<label class="cfg-field">
<span>Base URL</span>
<input id="cfg-f-url" placeholder="https://api.deepseek.com/v1">
<em>结尾不要带 /chat/completions</em>
</label>
<label class="cfg-field">
<span>API Key</span>
<input id="cfg-f-key" type="password" placeholder="sk-...">
<em id="cfg-f-key-hint">只存在你的服务器上,接口只回掩码</em>
</label>
<label class="cfg-field">
<span>模型名称</span>
<input id="cfg-f-model" placeholder="deepseek-chat">
</label>
<div class="cfg-presets">
<span>常用:</span>
<button type="button" class="cfg-preset" data-url="https://api.deepseek.com/v1" data-model="deepseek-chat">DeepSeek</button>
<button type="button" class="cfg-preset" data-url="https://dashscope.aliyuncs.com/compatible-mode/v1" data-model="qwen-plus">通义</button>
<button type="button" class="cfg-preset" data-url="https://open.bigmodel.cn/api/paas/v4" data-model="glm-4">智谱</button>
<button type="button" class="cfg-preset" data-url="https://api.openai.com/v1" data-model="gpt-4o-mini">OpenAI</button>
</div>
<div class="dialog-foot">
<button id="cfg-edit-cancel">取消</button>
<button class="primary" id="cfg-edit-save">保存</button>
</div>
</div>
</div>
<!-- ==================== AI 人设配置 ==================== -->
<div id="persona-cfg">
<div class="cfg-box">
<div class="cfg-head">
<h3>AI 人设配置</h3>
<div class="spacer"></div>
<button class="primary" id="persona-add">+ 新增</button>
<button id="persona-close">关闭</button>
</div>
<p class="cfg-tip">
人设决定助手的说话风格和做事规则。「默认」是代码里内置的那套,不能在这里改。
<br>提示词里<strong>不用写日期</strong> —— 今天是几号、「这个月」指哪个月,服务端每次对话会自动补上。
</p>
<div id="persona-list" class="cfg-list"></div>
</div>
</div>
<!-- ==================== 新增/编辑人设 ==================== -->
<div id="persona-edit">
<div class="dialog-box cfg-edit-box persona-edit-box">
<h3 id="persona-edit-title">新增人设</h3>
<label class="cfg-field">
<span>名称</span>
<input id="persona-f-name" placeholder="留空则取提示词开头几个字,比如:花花">
</label>
<label class="cfg-field">
<span>提示词</span>
<textarea id="persona-f-prompt" class="cfg-textarea"
placeholder="比如:你是一个说话简洁的记账助手…"></textarea>
<em id="persona-f-hint">人设 + 运行规则都写这里。日期由服务端自动补,不用写。</em>
</label>
<div class="cfg-warn" id="persona-warn" style="display:none"></div>
<div class="dialog-foot">
<button id="persona-restore">恢复默认</button>
<div class="spacer"></div>
<button id="persona-edit-cancel">取消</button>
<button class="primary" id="persona-edit-save">保存</button>
</div>
</div>
</div>
<!-- ==================== 相片大图查看 ==================== -->
<div id="photo-view">
<div class="pv-head">
<span class="pv-title" id="pv-title"></span>
<div class="spacer"></div>
<button id="pv-download">下载原图</button>
<button class="danger" id="pv-delete">删除</button>
<button id="pv-close">关闭</button>
</div>
<div class="pv-body">
<img id="pv-img" alt="">
</div>
<div class="pv-meta" id="pv-meta"></div>
</div>
<!-- ==================== 目录名输入 / 目录选择弹窗 ==================== -->
<div id="dialog">
<div class="dialog-box">
<h3 id="dialog-title">新建目录</h3>
<input id="dialog-input" placeholder="目录名">
<select id="dialog-select" style="display:none"></select>
<div class="dialog-foot">
<button id="dialog-cancel">取消</button>
<button class="primary" id="dialog-ok">确定</button>
</div>
</div>
</div>
<div id="toast"></div>
<!-- Vditor:本地托管,不依赖任何外部 CDN -->
<script src="/admin/vendor/vditor/dist/index.min.js"></script>
<!-- 图标名清单 + 兼容映射,由 qiangbao_accounting/tools/make_icons.py 生成 -->
<script src="/admin/icons.js"></script>
<script src="/admin/admin.js"></script>
</body>
</html>