优化go版本前后端连接问题
This commit is contained in:
1 parent
0cfeff4556
commit
c4b5a4ae41
3 files changed
+238
-51
No files matched your search
+1
-1
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# copy 打包结果到根目录的release/
|
||||
VERSION=1.0.0
|
||||
VERSION=1.0.2
|
||||
|
||||
if [ ! -d "./release" ]; then
|
||||
mkdir ./release
|
||||
|
||||
+33
-50
@@ -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)
|
||||
|
||||
@@ -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 单文件误报常见,添加信任或改用源码运行 |
|
||||
Reference in new issue
Block a user