数据库管理组件 — 实现文档
一、整体架构
┌──────────────────────────────────────────────────────────────┐
│ 用户界面(Vue 3) │
│ DatabaseManager.vue │
│ ┌────────────┐ ┌────────────┐ │
│ │ 远程数据库 │ │ 本地数据库 │ ← 仅桌面端显示 │
│ └─────┬──────┘ └─────┬──────┘ │
│ │ │ │
│ 浏览器: fetch 桌面端: window.lragent.* │
│ │ │ │
├────────┼───────────────┼─────────────────────────────────────┤
│ ▼ ▼ │
│ ┌──────────┐ ┌──────────────┐ │
│ │ 服务端API │ │ Electron IPC │ │
│ │ /api/ │ │ ipcMain │ │
│ │ platform │ │ .handle() │ │
│ └────┬─────┘ └──────┬───────┘ │
│ │ │ │
│ ▼ ▼ │
│ server/data/*.db ~/AppData/UserData/databases/*.db │
│ (远端服务器) (桌面端本地存储) │
└──────────────────────────────────────────────────────────────┘
核心思路:同一个 Vue 组件根据运行环境(浏览器 vs Electron 桌面端)自动选择不同的数据通道:
- 浏览器:直接调服务端 REST API
- 桌面端:通过
window.lragent.*(preload 桥接 → ipcMain handler)访问本地文件系统 + 远程 HTTP
二、三层实现详解
2.1 服务端(Node.js)— 远程数据源
文件:server/routes/platform-asset.js → handleDatabaseManagerRoutes()
数据目录:server/data/(由 DATA_DIR = path.join(__dirname, '..', 'data') 定义)
三个 API 端点:
| 端点 | 方法 | 功能 | 返回 |
|------|------|------|------|
| /api/platform/databases | GET | 列出所有 .db 文件 | { success, databases: [...], total } |
| /api/platform/databases/:name/download | GET | 下载 .db 文件 | application/octet-stream 流 |
| /api/platform/databases/:name/tables | GET | 查询表结构 | { success, tables: [{ name, sql, rowCount }] } |
列表 API 工作原理:
- 递归扫描
server/data/目录及子目录 - 找到所有
.db后缀文件 - 读取文件大小、修改时间
- 从
DB_DESCRIPTIONS字典匹配中文说明 - 按文件大小降序排列返回
下载 API 工作原理:
- 对文件名做安全过滤(去除
..、/、\,防路径穿越) - 拼接
DATA_DIR + safeName得到绝对路径 - 校验文件存在性
- 设置
Content-Type: application/octet-stream+Content-Disposition: attachment - 用
fs.createReadStream().pipe(res)流式传输
表结构 API 工作原理:
- 同样做路径安全过滤
- 用
better-sqlite3(或sqlite-compat)以只读模式打开 - 查询
sqlite_master获取所有用户表 - 对每个表执行
SELECT COUNT(*)获取行数 - 关闭数据库连接后返回
关键安全措施:
const safeName = dbName.replace(/\.\./g, '').replace(/[\/\\]/g, '');
防止路径穿越攻击。下载和表结构两个端点都做了此过滤。
2.2 桌面端(Electron)— 本地管理 + 远程同步
文件:electron-app/main.js → registerIpcHandlers()
本地存储目录:~/AppData/Roaming/lragent/databases/(由 app.getPath('userData') + '/databases' 定义)
6 个 IPC Handler:
| 通道 | 参数 | 功能 | 实现方式 |
|------|------|------|----------|
| db-list-local | 无 | 列出本地已下载的 .db | fs.readdirSync 扫描 dbStoreDir |
| db-list-remote | serverUrl? | 列出远程数据库 | HTTP GET → 先试 ylxt.chat,失败回退 localhost:3006 |
| db-download | dbName, serverUrl? | 下载远程 .db 到本地 | HTTP GET → fs.createWriteStream,带进度通知 |
| db-delete-local | dbName | 删除本地 .db | fs.unlinkSync |
| db-query | dbName, sql, params? | SQL 查询本地 .db | better-sqlite3 readonly 模式 |
| db-tables | dbName | 查看本地 .db 表结构 | better-sqlite3 + sqlite_master |
额外功能(preload 已暴露,组件暂未使用):
| 通道 | 功能 |
|------|------|
| db-export | 弹出保存对话框,复制本地 .db 到用户指定位置 |
| db-import | 弹出文件选择对话框,复制外部 .db 到本地存储 |
| db-store-path | 返回本地存储目录路径 |
下载进度通知:
mainWindow?.webContents.send('db-download-progress', {
dbName, status: 'downloading', received, total, percent
})
前端可通过 window.lragent.onDbDownloadProgress(cb) 监听。
远程连接的 fallback 逻辑:
db-list-remote / db-download:
1. 先尝试 https://ylxt.chat/api/platform/databases
2. 失败则回退 http://localhost:3006/api/platform/databases
3. 都失败返回合并错误信息
2.3 前端(Vue 3)— 统一交互界面
文件:src/views/DatabaseManager.vue
环境检测:
const isDesktop = !!(window.lragent && window.lragent.dbListRemote)
桌面端 preload.js 会注入 window.lragent 对象,浏览器环境不存在。
双 Tab 设计:
- 远程数据库 tab:浏览器和桌面端都显示
- 本地数据库 tab:仅桌面端显示(
v-if="isDesktop")
操作矩阵:
| 操作 | 浏览器·远程 | 桌面端·远程 | 桌面端·本地 |
|------|:-----------:|:-----------:|:-----------:|
| 浏览列表 | fetch API | IPC → HTTP | IPC → 本地 fs |
| 查看表结构 | fetch API | fetch API | IPC → better-sqlite3 |
| 下载 | 标签 | IPC → HTTP → 本地文件 | — |
| SQL 查询 | — | — | IPC → better-sqlite3 |
| 删除 | — | — | IPC → fs.unlink |
| 导入 | — | — | IPC → dialog (preload已暴露) |
| 导出 | — | — | IPC → dialog (preload已暴露) |
三、远端服务器需要做什么
3.1 最简方案:只放文件到指定目录
是的,放到指定目录就行。 服务端 API 会自动扫描。
步骤:
- 将
.db文件放到server/data/目录 - 如果有子目录分类(如
kb/、kb-snapshots/),API 会递归扫描 - 文件名后缀必须是
.db - 重启服务器即可生效(无缓存,实时扫描)
当前 server/data/ 已有的数据库(实测 27+ 个):
server/data/
├── bossagents.db (6.3 MB) 主业务数据库
├── rule_engine.db (353 MB) 规则引擎
├── boss_analytics.db (62 MB) 审计日志
├── digital-staff.db (1.5 MB) 数字员工
├── core_runtime.db (26 MB) 运行时主库
├── sciot-metadata.db (8 MB) SCSAI元数据
├── aml.db (4 MB) AML规则
├── inspection.db (2 MB) 巡检记录
├── sccapp_process_data.db (600 MB) 工艺规程
├── sciot_import.db (65 MB) SCSAI导入
├── kb/
│ └── phos_chem.db (247 MB) 磷化工知识库
├── kb-snapshots/
│ └── phos_chem_pre-convert_*.db 知识库快照
└── ... (共 27+ 个)
3.2 添加数据库说明
在 server/routes/platform-asset.js 的 DB_DESCRIPTIONS 字典中添加条目:
const DB_DESCRIPTIONS = {
'rule_engine.db': '规则引擎(巡检规则、模板、提示词)',
'bossagents.db': '主业务数据库',
// 添加新数据库的说明:
'your_new_db.db': '你的数据库说明',
};
不添加说明也能工作,说明列会显示 -。
3.3 官网部署(ylxt.chat)需要做的事
官网需要运行 LRAgent 的 Node.js 服务端,并确保:
必须项:
- 部署 server.js:
node server.js监听端口(默认 3006) - 放置 .db 文件:在
server/data/目录下放入要共享的数据库文件 - HTTPS:Electron 桌面端默认先连
https://ylxt.chat,需要 SSL 证书 - CORS(如果浏览器跨域访问):服务端已内置 CORS 中间件,无需额外配置
- 反向代理:如果用 Nginx,需要代理
/api/platform/databases*路径
Nginx 配置示例:
server {
listen 443 ssl;
server_name ylxt.chat;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# 数据库管理 API
location /api/platform/databases {
proxy_pass http://127.0.0.1:3006;
proxy_set_header Host $host;
proxy_read_timeout 300s; # 大文件下载需要长超时
proxy_buffering off; # 流式下载
client_max_body_size 0; # 不限制请求体
}
# 其他 API
location /api/ {
proxy_pass http://127.0.0.1:3006;
proxy_set_header Host $host;
}
# 前端静态文件
location / {
root /path/to/lragent/dist;
try_files $uri $uri/ /index.html;
}
}
大文件下载注意事项:
sccapp_process_data.db有 600MB,Nginx 默认proxy_buffering on会缓存整个响应- 必须设置
proxy_buffering off+proxy_read_timeout 300s - 或者用
X-Accel-Buffering: noheader 让 Nginx 不缓冲
3.4 不部署服务端的替代方案
如果官网不想运行 Node.js 服务端,可以用纯静态文件方式:
方案 A:Nginx 直接托管 .db 文件
location /databases/ {
alias /var/www/databases/;
autoindex on; # 开启目录列表
autoindex_format json; # JSON 格式目录列表
}
此方案需要修改桌面端 db-list-remote 的解析逻辑,因为返回格式不同。
方案 B:预生成数据库清单 JSON
- 写脚本定期扫描目录,生成
databases.json - 放到
https://ylxt.chat/databases.json - 下载链接指向
https://ylxt.chat/databases/xxx.db - 修改
db-list-remotehandler 解析此 JSON
方案 C:对象存储(OSS/S3)
- 将 .db 文件上传到 OSS bucket
- 生成一个
databases.json索引文件 - 下载链接指向 OSS 的签名 URL
- 适合 CDN 加速大文件下载
四、数据流详解
4.1 远程列表加载(浏览器)
用户打开页面
→ onMounted() → loadRemoteDatabases()
→ get('/api/platform/databases') ← src/utils/api.js (fetch)
→ Node.js server.js 路由匹配
→ handleDatabaseManagerRoutes()
→ scanDir('server/data/') ← 递归扫描
→ 返回 JSON { databases: [...] }
→ Vue 组件渲染表格
4.2 远程列表加载(桌面端)
用户打开页面
→ onMounted() → loadRemoteDatabases()
→ window.lragent.dbListRemote() ← preload.js 桥接
→ ipcMain.handle('db-list-remote')
→ httpGet('https://ylxt.chat/api/platform/databases')
→ 失败? → httpGet('http://localhost:3006/api/platform/databases')
→ JSON.parse(response)
→ 返回给渲染进程
→ Vue 组件渲染表格
4.3 下载到本地(桌面端)
用户点击"下载"
→ downloadDb(db)
→ window.lragent.dbDownload(db.name) ← preload.js 桥接
→ ipcMain.handle('db-download')
→ downloadFile('https://ylxt.chat/api/platform/databases/xxx.db/download', destPath)
→ HTTP 流式下载 → fs.createWriteStream
→ 进度通知: webContents.send('db-download-progress', {...})
→ 下载完成 → 返回 { success: true, path, size }
→ Vue 组件显示成功消息
4.4 本地 SQL 查询(桌面端)
用户点击"查询" → 输入 SQL → 点击"执行"
→ runQuery()
→ window.lragent.dbQuery(dbName, sql) ← preload.js 桥接
→ ipcMain.handle('db-query')
→ require('better-sqlite3')
→ new Database(dbPath, { readonly: true })
→ db.prepare(sql).all(...params)
→ db.close()
→ 返回 { success: true, rows: [...] }
→ Vue 组件渲染结果表格
五、安全设计
| 层级 | 措施 |
|------|------|
| 服务端路径 | dbName.replace(/\.\./g, '').replace(/[\/\\]/g, '') 防路径穿越 |
| 服务端下载 | 文件不存在返回 404,异常返回 500 |
| 服务端表查询 | better-sqlite3 以 readonly: true 打开,查询完立即关闭 |
| 桌面端查询 | readonly: true 模式,不允许写操作 |
| 桌面端删除 | 前端 confirm() 二次确认 |
| Electron | contextIsolation: true + nodeIntegration: false,preload 白名单暴露 |
六、扩展点
6.1 已实现但前端未接入的功能
| preload API | IPC 通道 | 功能 | 接入建议 |
|---|---|---|---|
| dbExport(dbName) | db-export | 导出本地 .db 到用户指定路径 | 本地 tab 加"导出"按钮 |
| dbImport() | db-import | 从外部导入 .db 到本地存储 | 本地 tab 加"导入"按钮 |
| dbStorePath() | db-store-path | 获取本地存储路径 | 工具栏显示 |
| onDbDownloadProgress(cb) | db-download-progress | 下载进度监听 | 下载按钮旁显示进度条 |
6.2 未来可扩展
- 增量同步:基于
mtime只下载有变化的 .db - 压缩传输:服务端 gzip 压缩 .db 文件(600MB → ~100MB)
- 权限控制:给
/api/platform/databases*加 API Key 验证 - 选择性同步:用户勾选需要的数据库,而非全量下载
- 定时同步:桌面端后台定时检查远端更新并自动同步
七、快速部署清单
官网服务器(ylxt.chat)
- [ ] 部署 LRAgent 服务端(
node server.js) - [ ] 将要共享的 .db 文件放入
server/data/ - [ ] 在
DB_DESCRIPTIONS中添加中文说明 - [ ] 配置 HTTPS 证书
- [ ] 配置 Nginx 反向代理(注意
proxy_buffering off和长超时) - [ ] 测试:
curl https://ylxt.chat/api/platform/databases返回 JSON
桌面端用户
- [ ] 安装 LRAgent 桌面客户端
- [ ] 打开"数据库管理"页面(侧边栏 → 系统管理 → 数据库管理)
- [ ] 在"远程数据库" tab 浏览、下载
- [ ] 在"本地数据库" tab 查看、查询、导出
浏览器用户
- [ ] 访问
https://ylxt.chat→ 侧边栏 → 数据库管理 - [ ] 浏览远程数据库列表、查看表结构
- [ ] 点击"下载"按钮下载 .db 文件到本地
BossAgents