mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-08-17 19:47:08 +08:00
feat: 本地 HTTP API + 设置面板 + 账号自助入口
让 WechatExplorer 既能用图形界面浏览聊天记录,也能作为本机 MCP 数据源被
Claude / Codex 等客户端通过 127.0.0.1:6131 直接拉取。
本机 HTTP API
- 新增 http-server: 8 个端点,覆盖 health / current_time / contact /
chatroom / recent_chat / chatlog / group_snapshot / resolve / report
- 时间参数支持 YYYY-MM-DD / YYYY-MM-DD/HH:mm / Unix 秒级;日期单独使用
时自动补到 00:00:00~23:59:59,避免漏消息
- apiServer 单例支持动态启停,启动失败返回 friendlyMessage(把
EADDRINUSE 翻译成"端口已被占用"的中文错误并附 4 次重试)
数据库根目录与自服务入口
- Wcdb4Client 接受 accountRoot 时会自动解析:父目录下找最新含
db_storage 的 wxid 子目录;设置面板"测试连接"成功后回写解析后的
精确路径
- 抽 chat-service.ts:IPC 和 HTTP 共享 listContacts / listMessages /
getGroupSnapshot / searchMessages / getSelfAccountInfo / testConnection
/ reopenWithRoot
- WechatDb 接受可选 accountRoot;设置面板新增"应用并重新初始化"
按钮,改完 dbRoot 立即生效
- 新增 settings-store.ts,dbRoot / apiEnabled / apiHost / apiPort 落到
userData/settings.json
主进程健壮性
- 新增 safe-log.ts 包一层 console.log/warn/error,electron-vite 关闭
子进程 stderr 后写 EPIPE 不再炸 IPC handler(原 main build 启动时
即 installSafeConsole)
This commit is contained in:
@@ -1204,3 +1204,359 @@ body {
|
||||
.voip-status {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Sidebar 自助卡片 + 入口 */
|
||||
.sidebar-footer {
|
||||
padding: 10px 12px;
|
||||
border-top: 1px solid var(--border-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
cursor: pointer;
|
||||
background-color: #f3f4f5;
|
||||
transition: background-color 0.15s ease;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.sidebar-footer:hover {
|
||||
background-color: #e6e9eb;
|
||||
}
|
||||
|
||||
.sidebar-self-avatar {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 6px;
|
||||
background-color: #07c160;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sidebar-self-avatar img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.sidebar-self-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar-self-nickname {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #1f2429;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.sidebar-self-wxid {
|
||||
font-size: 11px;
|
||||
color: #8a9298;
|
||||
margin-top: 2px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.sidebar-self-arrow {
|
||||
color: #8a9298;
|
||||
font-size: 18px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 设置面板 */
|
||||
.settings-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(15, 21, 26, 0.45);
|
||||
backdrop-filter: blur(2px);
|
||||
z-index: 1100;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
animation: settings-fade-in 0.16s ease-out;
|
||||
}
|
||||
|
||||
@keyframes settings-fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.settings-modal {
|
||||
width: min(560px, 92vw);
|
||||
max-height: 84vh;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 24px 60px rgba(15, 21, 26, 0.28);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
animation: settings-pop-in 0.18s ease-out;
|
||||
}
|
||||
|
||||
@keyframes settings-pop-in {
|
||||
from {
|
||||
transform: translateY(8px) scale(0.98);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.settings-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px 22px;
|
||||
border-bottom: 1px solid #ececec;
|
||||
}
|
||||
|
||||
.settings-header h2 {
|
||||
margin: 0;
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
color: #1f2429;
|
||||
}
|
||||
|
||||
.settings-close {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
color: #7d858a;
|
||||
font-size: 26px;
|
||||
line-height: 1;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.settings-close:hover {
|
||||
background: #f0f2f4;
|
||||
color: #1f2429;
|
||||
}
|
||||
|
||||
.settings-body {
|
||||
padding: 12px 22px 22px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.settings-section {
|
||||
margin-top: 14px;
|
||||
padding: 14px 16px;
|
||||
border-radius: 10px;
|
||||
background: #fafbfc;
|
||||
border: 1px solid #ececec;
|
||||
}
|
||||
|
||||
.settings-section:first-child {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.settings-section-title {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #6f767c;
|
||||
letter-spacing: 0.5px;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.settings-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.settings-row:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.settings-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: 8px 11px;
|
||||
border: 1px solid #d4d9dc;
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
font-size: 13px;
|
||||
color: #1f2429;
|
||||
font-family: 'SF Mono', Menlo, Consolas, monospace;
|
||||
outline: none;
|
||||
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||
}
|
||||
|
||||
.settings-input:focus {
|
||||
border-color: #07c160;
|
||||
box-shadow: 0 0 0 3px rgba(7, 193, 96, 0.12);
|
||||
}
|
||||
|
||||
.settings-input-half {
|
||||
flex: 0 1 140px;
|
||||
}
|
||||
|
||||
.settings-input-quarter {
|
||||
flex: 0 1 90px;
|
||||
}
|
||||
|
||||
.settings-btn {
|
||||
padding: 7px 14px;
|
||||
border: 1px solid #d4d9dc;
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
color: #30383d;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
transition: border-color 0.15s ease, background-color 0.15s ease, color 0.15s ease;
|
||||
}
|
||||
|
||||
.settings-btn:hover:not(:disabled) {
|
||||
border-color: #07c160;
|
||||
color: #078f49;
|
||||
}
|
||||
|
||||
.settings-btn:disabled {
|
||||
opacity: 0.55;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.settings-btn-primary {
|
||||
background: #07c160;
|
||||
color: #fff;
|
||||
border-color: #07c160;
|
||||
}
|
||||
|
||||
.settings-btn-primary:hover:not(:disabled) {
|
||||
background: #06ad56;
|
||||
color: #fff;
|
||||
border-color: #06ad56;
|
||||
}
|
||||
|
||||
.settings-hint {
|
||||
margin-top: 10px;
|
||||
font-size: 11px;
|
||||
color: #8a9298;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.settings-hint code {
|
||||
background: #eef0f2;
|
||||
padding: 1px 5px;
|
||||
border-radius: 3px;
|
||||
font-size: 10.5px;
|
||||
}
|
||||
|
||||
.settings-status {
|
||||
font-size: 12px;
|
||||
color: #59636a;
|
||||
}
|
||||
|
||||
.settings-status.ok {
|
||||
color: #078f49;
|
||||
}
|
||||
|
||||
.settings-status.fail {
|
||||
color: #c73737;
|
||||
}
|
||||
|
||||
.settings-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
color: #30383d;
|
||||
}
|
||||
|
||||
.settings-toggle input {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
accent-color: #07c160;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.settings-self {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.settings-self-avatar {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 10px;
|
||||
background: #07c160;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 22px;
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.settings-self-avatar img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.settings-self-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.settings-self-nickname {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #1f2429;
|
||||
}
|
||||
|
||||
.settings-self-wxid {
|
||||
font-size: 12px;
|
||||
color: #6f767c;
|
||||
margin-top: 2px;
|
||||
font-family: 'SF Mono', Menlo, Consolas, monospace;
|
||||
}
|
||||
|
||||
.settings-self-account {
|
||||
font-size: 11px;
|
||||
color: #8a9298;
|
||||
margin-top: 2px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.settings-self-empty {
|
||||
font-size: 13px;
|
||||
color: #8a9298;
|
||||
}
|
||||
|
||||
.settings-path {
|
||||
display: inline-block;
|
||||
font-family: 'SF Mono', Menlo, Consolas, monospace;
|
||||
font-size: 11px;
|
||||
background: #eef0f2;
|
||||
padding: 3px 7px;
|
||||
border-radius: 4px;
|
||||
color: #30383d;
|
||||
word-break: break-all;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user