优化go版本前后端连接问题

This commit is contained in:
maxf committed 2026-09-23 17:56:16 +08:00
1 parent 0cfeff4556
commit c4b5a4ae41
3 files changed
+238 -51

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
#!/bin/bash
# copy 打包结果到根目录的release/
VERSION=1.0.0
VERSION=1.0.2
if [ ! -d "./release" ]; then
mkdir ./release
+33 -50
View File
@@ -29,6 +29,8 @@ import (
"time"
"unsafe"
"golang.org/x/net/websocket"
"excel-search/internal/config"
"excel-search/internal/logging"
"excel-search/internal/model"
@@ -173,48 +175,7 @@ func main() {
shutdownOnce.Do(func() { close(shutdownCh) })
}
startTime := time.Now()
var hasConnected = false
var lastHeartbeat = time.Now()
var hbMu sync.Mutex
go func() {
ticker := time.NewTicker(3 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
}
hbMu.Lock()
connected := hasConnected
lastHb := lastHeartbeat
hbMu.Unlock()
if !connected {
if time.Since(startTime) > 120*time.Second {
slog.Info("startup timeout, shutting down", "reason", "no connection within 120s")
triggerShutdown()
return
}
continue
}
if time.Since(lastHb) > 300*time.Second {
slog.Info("frontend closed, shutting down", "reason", "heartbeat timeout")
triggerShutdown()
return
}
}
}()
// touchConnection 记录一次前端活动(任意页面/API 请求都算),供心跳判活。
touchConnection := func() {
hbMu.Lock()
hasConnected = true
lastHeartbeat = time.Now()
hbMu.Unlock()
}
touchConnection := func() {}
mux := http.NewServeMux()
// 样式表:返回内嵌的预编译 style.css
@@ -237,6 +198,23 @@ func main() {
})
// 心跳:前端周期性调用,维持“窗口仍打开”的判定(请求日志中间件已豁免此路径)
// WebSocket 生命周期长连接:前端建立连接后持续保持,一旦窗口关闭或断开,后端立即感知并关停
mux.Handle("/ws", websocket.Handler(func(ws *websocket.Conn) {
slog.Info("websocket client connected")
defer func() {
ws.Close()
slog.Info("websocket client disconnected, shutting down")
triggerShutdown()
}()
buf := make([]byte, 512)
for {
_, err := ws.Read(buf)
if err != nil {
break
}
}
}))
mux.HandleFunc("/api/close", func(w http.ResponseWriter, r *http.Request) {
slog.Info("received close notification from frontend, shutting down")
triggerShutdown()
@@ -873,12 +851,13 @@ const htmlUI = `<!DOCTYPE html>
checkHealth();
setInterval(checkHealth, 5000);
// 定时发送心跳保持后端存活,窗口关闭后停止发送
setInterval(async () => {
try {
await fetch('/api/heartbeat');
} catch(e) {}
}, 3000);
// 建立 WebSocket 长连接,实时绑定窗口生命周期:断开即关后端
function initWebSocket() {
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
const ws = new WebSocket(proto + '//' + location.host + '/ws');
ws.onclose = () => {};
}
initWebSocket();
// 页面卸载/关闭时使用 sendBeacon 立即通知后端退出
window.addEventListener('unload', () => {
@@ -1336,8 +1315,12 @@ func resizeAppWindowOnWindows() {
height := 720
x := (int(sw) - width) / 2
y := (int(sh) - height) / 2
if x < 0 { x = 0 }
if y < 0 { y = 0 }
if x < 0 {
x = 0
}
if y < 0 {
y = 0
}
// SWP_NOZORDER = 0x0004, SWP_NOACTIVATE = 0x0010
setWindowPos.Call(hwnd, 0, uintptr(x), uintptr(y), uintptr(width), uintptr(height), 0x0004|0x0010)
+204
View File
@@ -0,0 +1,204 @@
# Excel 关键字搜索工具(Python 版)
基于 **Python 3 + PyQt6** 的桌面 GUI 搜索工具,是三版本中功能最完整的早期主力版本:
在指定目录中批量检索 Excel / CSV / 文本文件里的关键字,结果以文件级列表呈现
(匹配数统计),并提供三版本中独有的**命中内容预览面板**(Excel 表格化渲染 / 文本高亮),
核对命中内容无需打开源文件。
- Python 版本要求:≥ 3.8(开发机实测 3.9)
- GUI 框架:PyQt6;Excel 读取:pandas / openpyxl / xlrd + 自研高速 XML 解析器
- 界面语言:简体中文 / 繁體中文 / English / 日本語(运行时菜单实时切换)
---
## 一、功能特性
- 🔍 **多线程并发搜索**:`ThreadPoolExecutor` 并行解析(默认 `min(8, max(2, CPU核数/2))`),UI 全程不卡顿
- 📁 **文件格式**:`.xlsx` `.xls` `.csv` `.txt`(`.docm` 等 Word 格式不支持,Word 需求请用 Go/Rust 版)
- 🎯 **搜索选项**:区分大小写、完整单词(正则 `\b`)、包含子目录、完整搜索
(取消勾选则每个 Sheet 只读前 1000 行提速)
- 👀 **命中内容预览**:选中结果行后,右侧面板表格化渲染命中 Sheet 的前 30 行预览;文本文件按行预览
- ⚡ **自研高速 xlsx 解析**:zip + XML 直读 sharedStrings/sheet,跳过 openpyxl 对超大样式表
(styles.xml 可达十几 MB)的解析;失败自动回退 pandas → openpyxl
- 🔤 **文本编码自适应**:utf-8-sig / utf-8 / cp932 / shift_jis / gb18030 / latin-1 逐级试探(覆盖日文 Shift-JIS 文档)
- 💾 **本地索引缓存**:按「路径+修改时间+大小+关键字+选项」缓存匹配数与预览,重复搜索秒回
- 📤 **导出 CSV**:当前搜索结果一键导出(全列双引号包裹、UTF-8 BOM,Excel 直接打开不乱码)
- 🖱️ **交互细节**:右键菜单(复制文件名/路径、打开文件/所在文件夹)、双击打开、目录历史下拉、
搜索进度条与耗时统计
- ⚙️ **设置持久化**:上次的目录/关键字/选项/目录历史经 QSettings 写入 Windows 注册表,重启自动恢复
### 快捷键
| 快捷键 | 功能 |
|---|---|
| `Ctrl+F` | 开始搜索 |
| `Ctrl+Shift+F` | 停止搜索 |
| `Ctrl+O` | 打开目录 |
| `Ctrl+Q` | 退出程序 |
---
## 二、目录结构与文件说明
```text
python/
├── main.py # 程序入口:QApplication 初始化 → MainWindow 启动事件循环
├── requirements.txt # pip 依赖清单(版本已锁定)
├── start.bat # 一键启动:首次自动检查 Python/pip 依赖并安装,之后直接启动 GUI
├── 重置环境.bat # 删除 .env_checked 标记,下次 start.bat 重新走环境检查
├── README.md # 本文件
│
├── src/ # 源代码包
│ ├── __init__.py # 包声明
│ ├── main_window.py # 【主窗口 ~(53KB)】界面搭建/信号槽/搜索调度/CSV导出/
│ │ # 设置持久化/QSS样式/语言切换/关于对话框,全部 MainWindow 类
│ ├── search_engine.py # 【搜索引擎 ~(27KB)】SearchEngine(QObject):
│ │ # 目录遍历、线程池并发、正则模式构建、
│ │ # xlsx高速XML/pandas/openpyxl 三级解析、xls(xlrd)、
│ │ # 文本多编码试探、.index 索引缓存读写、
│ │ # pyqtSignal: file_found / search_progress / search_finished / search_error
│ ├── components/
│ │ ├── __init__.py
│ │ └── file_table.py # FileTableWidget(QTableWidget):结果表格组件,
│ │ # 5 列(文件名/路径/大小/修改时间/匹配数)、右键菜单、
│ │ # file_data 列表即 CSV 导出的数据源
│ └── utils/
│ ├── __init__.py
│ ├── i18n.py # 国际化工具:简/繁/日/英 4 张翻译字典 + get_text/set_language,
│ │ # 语言变更回调机制(各组件注册后实时重刷 UI 文案)
│ └── logger.py # 日志初始化:logs/excel_search_<时间戳>.log(UTF-8)+ 控制台双输出
│
├── build/ # PyInstaller 中间产物(勿手动编辑,可安全删除)
├── dist/ # PyInstaller 产物:Excel关键字搜索工具.exe + logs/
└── .index/ # 搜索索引缓存(自动生成,键=目录MD5,可安全删除)
```
### 运行时生成的目录/文件(均可安全删除)
| 位置 | 内容 |
|---|---|
| `logs/excel_search_*.log` | 运行日志(相对启动目录生成,每次启动新建一份;exe 版在 exe 所在目录) |
| `python/.index/index_<目录MD5>.json` | 文件级搜索索引缓存(匹配数+offsets 预览) |
| `python/.env_checked` | start.bat 的环境检查标记(`重置环境.bat` 即删除它) |
| Windows 注册表 `HKCU\...\ProfessionalTools\ExcelKeywordSearch` | QSettings:上次目录/关键字/选项/目录历史/语言 |
---
## 三、依赖说明
`requirements.txt` 清单:
| 包 | 版本 | 实际用途 |
|---|---|---|
| PyQt6 | 6.6.1 | GUI 框架(必需) |
| pandas | 2.1.4 | xlsx 回退解析(必需) |
| openpyxl | 3.1.2 | pandas 的 xlsx 引擎 + 三级回退兜底(必需) |
| xlrd | 2.0.1 | .xls 旧格式解析(必需) |
| xlsxwriter | 3.1.9 | 预留(当前代码未直接调用) |
| python-docx | 1.1.0 | 预留(当前代码未直接调用,Word 搜索未实现) |
| Pillow | 10.1.0 | 预留(当前代码未直接调用) |
| qdarkstyle | 3.2.3 | 预留(当前使用自绘 QSS 明亮主题,未启用) |
> 精简派可只装前 4 个运行必需包;其余为历史迭代遗留,安装与否不影响功能。
---
## 四、运行步骤
### 方式一:一键脚本(推荐)
```bat
cd python
start.bat
```
首次运行自动完成:检查 Python → `pip install -r requirements.txt` → 写入 `.env_checked` 标记 → 启动 GUI。
之后再次运行直接启动(跳过检查)。环境异常时执行 `重置环境.bat` 后重试。
若需国内镜像加速,可先手动安装依赖:
```bat
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/
```
### 方式二:源码直接运行
```bat
cd python
python -m pip install -r requirements.txt
python main.py
```
### 方式三:使用已打包 exe
`python\dist\Excel关键字搜索工具.exe`(约 300 MB,免 Python 环境,双击即用)。
日志目录 `logs/` 生成在 exe 所在目录。
---
## 五、打包步骤(PyInstaller)
在 `python/` 目录、目标 Python 环境内执行:
```bat
pip install pyinstaller
pyinstaller --noconsole --onefile --name="Excel关键字搜索工具" main.py
```
- `--onefile`:所有依赖与代码压入单个 exe,便于分发
- `--noconsole`:隐藏黑底控制台(GUI 应用)
- `--name`:指定产物名;产物输出到 `dist\Excel关键字搜索工具.exe`
> 可选:添加 `--icon=icon.ico` 注入图标。
> 注意:PyInstaller 打包体积 ≈ 300 MB(pandas/PyQt6 依赖较重)且首次启动需解包,
> 属正常现象。打包环境尽量与目标机器 Python 版本一致。
---
## 六、开发说明
### 修改界面 / 增加功能
- 界面与交互集中在 `main_window.py`(MainWindow 类按面板拆分为
`create_search_panel / create_results_panel / create_details_panel / create_status_bar / create_menu_bar`);
样式在 `apply_styles()`(纯 QSS 字符串,明亮主题)。
- 搜索逻辑改动在 `search_engine.py`;注意搜索引擎实例经 `moveToThread` 挂到 QThread,
与主线程仅通过 `pyqtSignal` 通信,不要在引擎内直接操作控件。
### 新增界面文案(i18n)
1. 代码中用 `get_text("English key")` 取文案(英文原文作键);
2. 在 `src/utils/i18n.py` 的 4 张字典(CHINESE / TRADITIONAL / JAPANESE / ENGLISH_TRANSLATIONS)中
各补一条同键翻译;
3. 动态刷新组件需注册 `register_language_change_callback`(参考 FileTableWidget.update_language)。
### 新增文件格式支持
`search_engine.py` 的 `_is_excel_file()` 加扩展名,`_search_file()` 的分派分支加解析器入口,
必要时扩展 `_preview_type()`。
### 导出 CSV 说明
`MainWindow.export_results_csv()`:`csv.writer(quoting=csv.QUOTE_ALL)` + `utf-8-sig` 编码写出
`components/file_table.py` 的 `file_data`(界面表格数据源,所见即所导):
- 全列双引号包裹,字段内 `"` 自动转义为 `""`(RFC 4180);
- UTF-8 BOM + CRLF,Excel 双击打开中文/日文不乱码;
- 表头随当前界面语言输出(跟随所选语言的列名翻译)。
### 调试
日志默认 INFO 级别写入 `logs/`;调整级别改 `src/utils/logger.py` 的 `logging.basicConfig(level=...)`。
---
## 七、常见问题
| 症状 | 处理 |
|---|---|
| start.bat 提示未找到 Python | 安装 Python ≥ 3.8 并勾选 *Add to PATH*,或从 python.org 重装后重试 |
| 依赖安装失败 / 网络慢 | 使用清华镜像:`pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/` |
| 环境状态混乱 | 双击 `重置环境.bat` 后重新 `start.bat` |
| 搜索慢 | 勾选「包含子目录」时缩小目录范围;取消「完整搜索」只读前 1000 行;确认缓存目录 `.index/` 可写 |
| 搜索结果不对 | 修改文件后缓存按 mtime+size 自动失效;仍异常可删除 `python/.index/` 强制重建 |
| exe 被杀毒软件拦截 | PyInstaller 单文件误报常见,添加信任或改用源码运行 |