389 lines
17 KiB
HTML
389 lines
17 KiB
HTML
<!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>
|