Compare commits
4 Commits
e66a6cec84
...
b437f3ffc1
Author | SHA1 | Date | |
---|---|---|---|
b437f3ffc1 | |||
18d7a4d0a1 | |||
0336d55682 | |||
84f11a0906 |
89
.github/workflows/main.yml
vendored
Normal file
89
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
# GitHub Actions工作流 - 多平台构建
|
||||
# 将此文件放在 .github/workflows/ 目录下
|
||||
|
||||
name: Build Multi-Platform Executables
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-windows:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x64, x86]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
architecture: ${{ matrix.arch }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install pandas openpyxl pyinstaller
|
||||
|
||||
- name: Build executable
|
||||
run: |
|
||||
pyinstaller --onefile --console --name "座位分配系统_${{ matrix.arch }}" seat_allocation_system.py
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows-${{ matrix.arch }}
|
||||
path: dist/座位分配系统_${{ matrix.arch }}.exe
|
||||
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install pandas openpyxl pyinstaller
|
||||
|
||||
- name: Build executable
|
||||
run: |
|
||||
pyinstaller --onefile --console --name "座位分配系统_macos" seat_allocation_system.py
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macos
|
||||
path: dist/座位分配系统_macos
|
||||
|
||||
create-release:
|
||||
needs: [build-windows, build-macos]
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
|
||||
steps:
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: v${{ github.run_number }}
|
||||
name: Release v${{ github.run_number }}
|
||||
files: |
|
||||
windows-x64/座位分配系统_x64.exe
|
||||
windows-x86/座位分配系统_x86.exe
|
||||
macos/座位分配系统_macos
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
284
Windows部署说明.md
Normal file
284
Windows部署说明.md
Normal file
@@ -0,0 +1,284 @@
|
||||
# 座位分配系统 - Windows部署说明
|
||||
|
||||
## 目录
|
||||
- [概述](#概述)
|
||||
- [系统要求](#系统要求)
|
||||
- [开发者构建指南](#开发者构建指南)
|
||||
- [用户使用指南](#用户使用指南)
|
||||
- [故障排除](#故障排除)
|
||||
- [技术支持](#技术支持)
|
||||
|
||||
## 概述
|
||||
|
||||
本文档说明如何在Windows系统上构建和部署座位分配系统。该系统支持1-10人连坐需求,能够处理不连续座位分配。
|
||||
|
||||
**主要功能:**
|
||||
- 智能座位分配算法
|
||||
- 支持连坐组合(1-10人)
|
||||
- 完整的文件校验
|
||||
- 详细的分配日志
|
||||
- 用户友好的命令行界面
|
||||
|
||||
## 系统要求
|
||||
|
||||
### 开发环境要求
|
||||
- **操作系统**: Windows 7/10/11 (64位)
|
||||
- **Python版本**: Python 3.8 或更高版本
|
||||
- **内存**: 至少 2GB RAM
|
||||
- **磁盘空间**: 至少 500MB 可用空间
|
||||
- **网络**: 需要网络连接以下载依赖包
|
||||
|
||||
### 运行环境要求(最终用户)
|
||||
- **操作系统**: Windows 7/10/11 (64位)
|
||||
- **内存**: 至少 1GB RAM
|
||||
- **磁盘空间**: 至少 100MB 可用空间
|
||||
- **Excel**: Microsoft Excel 2010 或更高版本(查看结果文件)
|
||||
|
||||
## 开发者构建指南
|
||||
|
||||
### 1. 环境准备
|
||||
|
||||
#### 1.1 安装Python
|
||||
从 [Python官网](https://www.python.org/downloads/) 下载并安装Python 3.8+
|
||||
|
||||
确保安装时勾选:
|
||||
- ✅ Add Python to PATH
|
||||
- ✅ Install pip
|
||||
|
||||
#### 1.2 验证安装
|
||||
```cmd
|
||||
python --version
|
||||
pip --version
|
||||
```
|
||||
|
||||
### 2. 下载源代码
|
||||
|
||||
```cmd
|
||||
git clone <repository-url>
|
||||
cd TableSynthesis
|
||||
```
|
||||
|
||||
### 3. 自动构建(推荐)
|
||||
|
||||
#### 3.1 运行构建脚本
|
||||
```cmd
|
||||
python windows_build.py
|
||||
```
|
||||
|
||||
构建脚本将自动完成:
|
||||
- ✅ 检查系统环境
|
||||
- ✅ 安装必要依赖
|
||||
- ✅ 构建独立exe文件
|
||||
- ✅ 创建分发包
|
||||
|
||||
#### 3.2 构建输出
|
||||
构建成功后,会生成:
|
||||
```
|
||||
座位分配系统_Windows_分发包/
|
||||
├── 座位分配系统.exe # 主程序
|
||||
├── 运行座位分配系统.bat # 启动脚本
|
||||
├── 使用说明.txt # 使用说明
|
||||
├── 人员信息_示例.xlsx # 示例文件
|
||||
└── 座位信息_示例.xlsx # 示例文件
|
||||
```
|
||||
|
||||
### 4. 手动构建(可选)
|
||||
|
||||
如果自动构建失败,可以手动构建:
|
||||
|
||||
#### 4.1 安装依赖
|
||||
```cmd
|
||||
pip install pandas>=1.3.0 openpyxl>=3.0.0 numpy>=1.20.0 pyinstaller>=4.0
|
||||
```
|
||||
|
||||
#### 4.2 使用PyInstaller构建
|
||||
```cmd
|
||||
pyinstaller --clean --noconfirm seat_allocation.spec
|
||||
```
|
||||
|
||||
#### 4.3 手动创建分发包
|
||||
```cmd
|
||||
mkdir 座位分配系统_Windows_分发包
|
||||
copy dist\座位分配系统.exe 座位分配系统_Windows_分发包\
|
||||
copy 人员信息.xlsx 座位分配系统_Windows_分发包\人员信息_示例.xlsx
|
||||
copy 座位信息.xlsx 座位分配系统_Windows_分发包\座位信息_示例.xlsx
|
||||
copy 运行座位分配系统.bat 座位分配系统_Windows_分发包\
|
||||
```
|
||||
|
||||
## 用户使用指南
|
||||
|
||||
### 1. 获取分发包
|
||||
|
||||
从开发者处获取 `座位分配系统_Windows_分发包` 文件夹,或下载已构建的发布版本。
|
||||
|
||||
### 2. 准备数据文件
|
||||
|
||||
#### 2.1 复制示例文件
|
||||
```
|
||||
人员信息_示例.xlsx → 人员信息.xlsx
|
||||
座位信息_示例.xlsx → 座位信息.xlsx
|
||||
```
|
||||
|
||||
#### 2.2 填写人员信息.xlsx
|
||||
|
||||
**必需列:**
|
||||
- **姓名**: 人员姓名
|
||||
- **证件类型**: 身份证、护照等
|
||||
- **证件号**: 证件号码
|
||||
- **手机号**: 联系电话
|
||||
- **备注**: 连坐人数(留空表示单独坐)
|
||||
|
||||
**连坐规则:**
|
||||
- 单人坐位:备注列留空
|
||||
- 连坐组合:第一人填写总人数,其他人留空
|
||||
|
||||
**示例:**
|
||||
| 姓名 | 证件类型 | 证件号 | 手机号 | 备注 |
|
||||
|------|----------|--------|--------|------|
|
||||
| 张三 | 身份证 | 123456789012345678 | 13800138000 | 3 |
|
||||
| 李四 | 身份证 | 123456789012345679 | 13800138001 | |
|
||||
| 王五 | 身份证 | 123456789012345680 | 13800138002 | |
|
||||
| 赵六 | 身份证 | 123456789012345681 | 13800138003 | |
|
||||
|
||||
上述示例表示:张三、李四、王五需要3人连坐,赵六单独坐。
|
||||
|
||||
#### 2.3 填写座位信息.xlsx
|
||||
|
||||
**必需列:**
|
||||
- **区域**: 座位区域(如"A区"、"B区")
|
||||
- **楼层**: 楼层信息(如"1层"、"2层")
|
||||
- **排号**: 排号(如"第1排"、"第2排")
|
||||
- **座位号**: 具体座位号(如"1号"、"2号")
|
||||
|
||||
**示例:**
|
||||
| 区域 | 楼层 | 排号 | 座位号 |
|
||||
|------|------|------|--------|
|
||||
| A区 | 1层 | 第1排 | 1号 |
|
||||
| A区 | 1层 | 第1排 | 2号 |
|
||||
| A区 | 1层 | 第1排 | 3号 |
|
||||
|
||||
### 3. 运行程序
|
||||
|
||||
#### 3.1 推荐方式(使用bat脚本)
|
||||
双击 `运行座位分配系统.bat`
|
||||
|
||||
脚本会自动:
|
||||
- ✅ 检查环境和文件
|
||||
- ✅ 提供友好的错误提示
|
||||
- ✅ 运行主程序
|
||||
- ✅ 显示运行结果
|
||||
|
||||
#### 3.2 直接运行
|
||||
双击 `座位分配系统.exe`
|
||||
|
||||
### 4. 查看结果
|
||||
|
||||
程序运行成功后,会生成以下文件:
|
||||
|
||||
- **座位信息_最终分配.xlsx**: 最终座位分配结果
|
||||
- **最终座位分配日志.xlsx**: 详细分配记录
|
||||
- **seat_allocation_log.txt**: 运行日志
|
||||
|
||||
使用Excel打开xlsx文件查看分配结果。
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
#### Q1: 程序无法启动
|
||||
**可能原因:**
|
||||
- 系统不兼容(需要Windows 7+)
|
||||
- 缺少Visual C++ Redistributable
|
||||
|
||||
**解决方案:**
|
||||
1. 确认系统版本:Windows 7/10/11 64位
|
||||
2. 下载安装 [Microsoft Visual C++ Redistributable](https://aka.ms/vs/17/release/vc_redist.x64.exe)
|
||||
|
||||
#### Q2: 提示缺少依赖包
|
||||
**可能原因:**
|
||||
- 网络连接问题
|
||||
- 权限不足
|
||||
|
||||
**解决方案:**
|
||||
1. 确保网络连接正常
|
||||
2. 以管理员身份运行
|
||||
3. 手动安装:`pip install pandas openpyxl numpy`
|
||||
|
||||
#### Q3: 文件权限错误
|
||||
**可能原因:**
|
||||
- Excel文件被占用
|
||||
- 程序目录只读
|
||||
|
||||
**解决方案:**
|
||||
1. 关闭所有Excel窗口
|
||||
2. 确保程序目录有写入权限
|
||||
3. 避免在系统盘根目录运行
|
||||
|
||||
#### Q4: 数据文件格式错误
|
||||
**可能原因:**
|
||||
- 列名不匹配
|
||||
- 数据类型错误
|
||||
- 编码问题
|
||||
|
||||
**解决方案:**
|
||||
1. 对照示例文件检查列名
|
||||
2. 确保数据格式正确
|
||||
3. 使用UTF-8编码保存
|
||||
|
||||
#### Q5: 无法找到连续座位
|
||||
**可能原因:**
|
||||
- 座位信息不连续
|
||||
- 连坐组过大
|
||||
|
||||
**解决方案:**
|
||||
1. 检查座位信息的连续性
|
||||
2. 适当调整连坐组大小
|
||||
3. 增加座位数量
|
||||
|
||||
### 日志分析
|
||||
|
||||
查看 `seat_allocation_log.txt` 文件可获取详细错误信息:
|
||||
|
||||
- **文件加载错误**: 检查文件路径和格式
|
||||
- **数据校验错误**: 检查数据完整性
|
||||
- **分配算法错误**: 检查座位和人员匹配
|
||||
|
||||
### 性能优化
|
||||
|
||||
#### 大数据处理
|
||||
- **人员数量**: 建议不超过1000人
|
||||
- **座位数量**: 建议不超过2000个
|
||||
- **连坐组大小**: 建议不超过8人
|
||||
|
||||
#### 内存使用
|
||||
- 小型场景(<100人): 约50MB内存
|
||||
- 中型场景(100-500人): 约100MB内存
|
||||
- 大型场景(500-1000人): 约200MB内存
|
||||
|
||||
## 技术支持
|
||||
|
||||
### 获取帮助
|
||||
|
||||
1. **查看日志文件**: `seat_allocation_log.txt`
|
||||
2. **检查使用说明**: `使用说明.txt`
|
||||
3. **参考示例文件**: 确保数据格式正确
|
||||
|
||||
### 报告问题
|
||||
|
||||
报告问题时,请提供:
|
||||
- 系统信息(操作系统版本)
|
||||
- 错误截图或错误信息
|
||||
- 数据文件(脱敏后)
|
||||
- seat_allocation_log.txt 内容
|
||||
|
||||
### 更新与维护
|
||||
|
||||
- 定期检查更新版本
|
||||
- 备份重要数据文件
|
||||
- 保持系统和依赖包更新
|
||||
|
||||
---
|
||||
|
||||
**版本**: v1.0
|
||||
**最后更新**: 2024年12月
|
||||
**兼容性**: Windows 7/10/11 (64位)
|
@@ -6,11 +6,91 @@
|
||||
支持1-10人连坐需求,能够处理不连续座位
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
import datetime
|
||||
import sys
|
||||
|
||||
def check_dependencies():
|
||||
"""检查并安装必要的依赖包"""
|
||||
required_packages = {
|
||||
'pandas': 'pandas>=1.3.0',
|
||||
'numpy': 'numpy>=1.20.0',
|
||||
'openpyxl': 'openpyxl>=3.0.0'
|
||||
}
|
||||
|
||||
missing_packages = []
|
||||
|
||||
print("检查依赖包...")
|
||||
for package_name, package_spec in required_packages.items():
|
||||
try:
|
||||
__import__(package_name)
|
||||
print(f"✅ {package_name} 已安装")
|
||||
except ImportError:
|
||||
missing_packages.append(package_spec)
|
||||
print(f"❌ {package_name} 未安装")
|
||||
|
||||
if missing_packages:
|
||||
print(f"\n发现缺失依赖: {', '.join(missing_packages)}")
|
||||
print("正在尝试自动安装...")
|
||||
|
||||
try:
|
||||
import subprocess
|
||||
for package in missing_packages:
|
||||
print(f"安装 {package}...")
|
||||
result = subprocess.run([sys.executable, '-m', 'pip', 'install', package],
|
||||
capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
print(f"✅ {package} 安装成功")
|
||||
else:
|
||||
print(f"❌ {package} 安装失败: {result.stderr}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"❌ 自动安装失败: {e}")
|
||||
print("\n请手动安装以下依赖包:")
|
||||
for package in missing_packages:
|
||||
print(f" pip install {package}")
|
||||
input("安装完成后按Enter键继续...")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def check_data_files():
|
||||
"""检查必要的数据文件"""
|
||||
required_files = ['人员信息.xlsx', '座位信息.xlsx']
|
||||
missing_files = []
|
||||
|
||||
print("\n检查数据文件...")
|
||||
for file_name in required_files:
|
||||
if Path(file_name).exists():
|
||||
print(f"✅ {file_name} 存在")
|
||||
else:
|
||||
missing_files.append(file_name)
|
||||
print(f"❌ {file_name} 不存在")
|
||||
|
||||
if missing_files:
|
||||
print(f"\n❌ 缺少必要文件: {', '.join(missing_files)}")
|
||||
print("\n请确保以下文件存在于程序同一目录下:")
|
||||
print("1. 人员信息.xlsx - 包含姓名、证件类型、证件号、手机号、备注等列")
|
||||
print("2. 座位信息.xlsx - 包含区域、楼层、排号、座位号等列")
|
||||
print("\n提示: 您可以参考示例文件来准备数据")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
# 只有在依赖检查通过后才导入这些包
|
||||
if check_dependencies():
|
||||
try:
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
except ImportError as e:
|
||||
print(f"❌ 导入依赖包失败: {e}")
|
||||
input("按Enter键退出...")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("❌ 依赖检查失败")
|
||||
input("按Enter键退出...")
|
||||
sys.exit(1)
|
||||
|
||||
class Logger:
|
||||
"""日志记录器"""
|
||||
@@ -32,7 +112,7 @@ class Logger:
|
||||
try:
|
||||
with open(self.log_file, 'w', encoding='utf-8') as f:
|
||||
f.write('\n'.join(self.logs))
|
||||
self.log(f"日志已保存到: {self.log_file}")
|
||||
print(f"日志已保存到: {self.log_file}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"保存日志失败: {e}")
|
||||
@@ -879,20 +959,54 @@ class SeatAllocationSystem:
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
system = SeatAllocationSystem()
|
||||
|
||||
print("=" * 60)
|
||||
print("座位分配系统 v1.0")
|
||||
print("=" * 60)
|
||||
|
||||
try:
|
||||
# 检查数据文件
|
||||
if not check_data_files():
|
||||
input("\n按Enter键退出...")
|
||||
return
|
||||
|
||||
print("\n开始运行座位分配系统...")
|
||||
system = SeatAllocationSystem()
|
||||
|
||||
# 运行校验
|
||||
if system.run_validation():
|
||||
# 校验通过,运行分配
|
||||
system.run_allocation()
|
||||
# 校验通过,询问是否继续分配
|
||||
response = input("\n文件校验通过,是否开始座位分配? (Y/n): ")
|
||||
if response.lower() in ['', 'y', 'yes']:
|
||||
# 运行分配
|
||||
if system.run_allocation():
|
||||
print("\n🎉 座位分配完成!")
|
||||
print("请查看以下输出文件:")
|
||||
print("- 座位信息_最终分配.xlsx (分配结果)")
|
||||
print("- 最终座位分配日志.xlsx (详细日志)")
|
||||
print("- seat_allocation_log.txt (运行日志)")
|
||||
else:
|
||||
print("\n❌ 座位分配失败!")
|
||||
else:
|
||||
print("用户取消座位分配")
|
||||
else:
|
||||
print("\n❌ 文件校验失败,请修复问题后重试")
|
||||
|
||||
# 保存日志
|
||||
system.logger.save_logs()
|
||||
|
||||
except FileNotFoundError as e:
|
||||
print(f"\n❌ 文件未找到: {e}")
|
||||
print("请确保所有必要文件都在程序目录下")
|
||||
except PermissionError as e:
|
||||
print(f"\n❌ 文件权限错误: {e}")
|
||||
print("请确保程序有读写文件的权限")
|
||||
except Exception as e:
|
||||
system.logger.log(f"系统运行出错: {e}")
|
||||
system.logger.save_logs()
|
||||
print(f"\n❌ 程序运行出错: {e}")
|
||||
print("请检查数据文件格式是否正确")
|
||||
|
||||
finally:
|
||||
# 等待用户确认后退出
|
||||
input("\n程序结束,按Enter键退出...")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
496
windows_build.py
Normal file
496
windows_build.py
Normal file
@@ -0,0 +1,496 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Windows专用构建脚本
|
||||
自动检测依赖、构建独立exe文件并创建分发包
|
||||
适用于Windows 7/10/11 (x64)
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import platform
|
||||
import shutil
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
class WindowsBuilder:
|
||||
"""Windows构建器"""
|
||||
|
||||
def __init__(self):
|
||||
self.project_root = Path.cwd()
|
||||
self.dist_dir = self.project_root / 'dist'
|
||||
self.build_dir = self.project_root / 'build'
|
||||
self.package_dir = self.project_root / '座位分配系统_Windows_分发包'
|
||||
|
||||
def check_environment(self):
|
||||
"""检查构建环境"""
|
||||
print("=" * 60)
|
||||
print("Windows构建环境检查")
|
||||
print("=" * 60)
|
||||
|
||||
# 检查操作系统
|
||||
if platform.system() != 'Windows':
|
||||
print(f"❌ 当前系统: {platform.system()}")
|
||||
print("此脚本仅适用于Windows系统")
|
||||
return False
|
||||
|
||||
print(f"✅ 操作系统: {platform.system()} {platform.release()}")
|
||||
print(f"✅ 架构: {platform.machine()}")
|
||||
print(f"✅ Python版本: {sys.version}")
|
||||
|
||||
# 检查主程序文件
|
||||
main_script = self.project_root / 'seat_allocation_system.py'
|
||||
if not main_script.exists():
|
||||
print("❌ 未找到主程序文件: seat_allocation_system.py")
|
||||
return False
|
||||
print(f"✅ 主程序文件存在: {main_script}")
|
||||
|
||||
return True
|
||||
|
||||
def install_dependencies(self):
|
||||
"""安装构建依赖"""
|
||||
print("\n" + "=" * 60)
|
||||
print("安装构建依赖")
|
||||
print("=" * 60)
|
||||
|
||||
required_packages = [
|
||||
'pandas>=1.3.0',
|
||||
'openpyxl>=3.0.0',
|
||||
'numpy>=1.20.0',
|
||||
'pyinstaller>=4.0'
|
||||
]
|
||||
|
||||
for package in required_packages:
|
||||
print(f"\n检查 {package}...")
|
||||
package_name = package.split('>=')[0]
|
||||
|
||||
try:
|
||||
__import__(package_name)
|
||||
print(f"✅ {package_name} 已安装")
|
||||
except ImportError:
|
||||
print(f"📦 安装 {package}...")
|
||||
try:
|
||||
cmd = [sys.executable, '-m', 'pip', 'install', package, '--user']
|
||||
result = subprocess.run(cmd, capture_output=True, text=True,
|
||||
encoding='utf-8', errors='ignore')
|
||||
|
||||
if result.returncode == 0:
|
||||
print(f"✅ {package} 安装成功")
|
||||
else:
|
||||
print(f"❌ {package} 安装失败")
|
||||
print(f"错误信息: {result.stderr}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"❌ 安装过程出错: {e}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def clean_build_dirs(self):
|
||||
"""清理构建目录"""
|
||||
print("\n清理构建目录...")
|
||||
|
||||
for dir_path in [self.dist_dir, self.build_dir]:
|
||||
if dir_path.exists():
|
||||
try:
|
||||
shutil.rmtree(dir_path)
|
||||
print(f"✅ 清理目录: {dir_path}")
|
||||
except Exception as e:
|
||||
print(f"⚠️ 清理目录失败 {dir_path}: {e}")
|
||||
|
||||
# 清理spec文件
|
||||
for spec_file in self.project_root.glob('*.spec'):
|
||||
try:
|
||||
spec_file.unlink()
|
||||
print(f"✅ 清理spec文件: {spec_file}")
|
||||
except Exception as e:
|
||||
print(f"⚠️ 清理spec文件失败 {spec_file}: {e}")
|
||||
|
||||
def create_spec_file(self):
|
||||
"""创建PyInstaller配置文件"""
|
||||
print("\n创建PyInstaller配置文件...")
|
||||
|
||||
spec_content = '''# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
block_cipher = None
|
||||
|
||||
a = Analysis(
|
||||
['seat_allocation_system.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[
|
||||
'pandas',
|
||||
'openpyxl',
|
||||
'numpy',
|
||||
'xlsxwriter',
|
||||
'xlrd',
|
||||
'datetime',
|
||||
'pathlib',
|
||||
'openpyxl.workbook',
|
||||
'openpyxl.worksheet',
|
||||
'openpyxl.styles'
|
||||
],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[
|
||||
'matplotlib',
|
||||
'scipy',
|
||||
'IPython',
|
||||
'jupyter',
|
||||
'notebook',
|
||||
'tkinter',
|
||||
'PyQt5',
|
||||
'PyQt6',
|
||||
'PySide2',
|
||||
'PySide6'
|
||||
],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False,
|
||||
)
|
||||
|
||||
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
name='座位分配系统',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=False,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
)
|
||||
'''
|
||||
|
||||
spec_file = self.project_root / 'seat_allocation.spec'
|
||||
with open(spec_file, 'w', encoding='utf-8') as f:
|
||||
f.write(spec_content)
|
||||
|
||||
print(f"✅ 配置文件已创建: {spec_file}")
|
||||
return spec_file
|
||||
|
||||
def build_executable(self, spec_file):
|
||||
"""构建可执行文件"""
|
||||
print("\n" + "=" * 60)
|
||||
print("开始构建可执行文件")
|
||||
print("=" * 60)
|
||||
|
||||
cmd = [
|
||||
sys.executable, '-m', 'PyInstaller',
|
||||
'--clean',
|
||||
'--noconfirm',
|
||||
str(spec_file)
|
||||
]
|
||||
|
||||
print(f"执行命令: {' '.join(cmd)}")
|
||||
print("这可能需要几分钟时间,请耐心等待...")
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
try:
|
||||
# 使用Popen来实时显示输出
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
universal_newlines=True,
|
||||
encoding='utf-8',
|
||||
errors='ignore'
|
||||
)
|
||||
|
||||
# 实时显示输出
|
||||
for line in process.stdout:
|
||||
line = line.strip()
|
||||
if line:
|
||||
if 'WARNING' in line:
|
||||
print(f"⚠️ {line}")
|
||||
elif 'ERROR' in line:
|
||||
print(f"❌ {line}")
|
||||
elif 'Building' in line or 'Analyzing' in line:
|
||||
print(f"🔄 {line}")
|
||||
elif 'completed successfully' in line:
|
||||
print(f"✅ {line}")
|
||||
|
||||
# 等待进程完成
|
||||
return_code = process.wait()
|
||||
|
||||
build_time = time.time() - start_time
|
||||
|
||||
if return_code == 0:
|
||||
print(f"\n✅ 构建成功! 耗时: {build_time:.1f}秒")
|
||||
|
||||
# 检查生成的文件
|
||||
exe_path = self.dist_dir / '座位分配系统.exe'
|
||||
if exe_path.exists():
|
||||
file_size = exe_path.stat().st_size / (1024 * 1024) # MB
|
||||
print(f"✅ 生成文件: {exe_path}")
|
||||
print(f"✅ 文件大小: {file_size:.1f} MB")
|
||||
return True, exe_path
|
||||
else:
|
||||
print("❌ 未找到生成的exe文件")
|
||||
return False, None
|
||||
else:
|
||||
print(f"\n❌ 构建失败! 返回码: {return_code}")
|
||||
return False, None
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 构建过程中出现错误: {e}")
|
||||
return False, None
|
||||
|
||||
def create_distribution_package(self, exe_path):
|
||||
"""创建分发包"""
|
||||
print("\n" + "=" * 60)
|
||||
print("创建分发包")
|
||||
print("=" * 60)
|
||||
|
||||
# 清理之前的分发包
|
||||
if self.package_dir.exists():
|
||||
shutil.rmtree(self.package_dir)
|
||||
|
||||
self.package_dir.mkdir()
|
||||
print(f"✅ 创建分发目录: {self.package_dir}")
|
||||
|
||||
# 复制可执行文件
|
||||
dest_exe = self.package_dir / exe_path.name
|
||||
shutil.copy2(exe_path, dest_exe)
|
||||
print(f"✅ 复制可执行文件: {exe_path.name}")
|
||||
|
||||
# 复制示例文件(如果存在)
|
||||
example_files = [
|
||||
('人员信息.xlsx', '人员信息_示例.xlsx'),
|
||||
('座位信息.xlsx', '座位信息_示例.xlsx')
|
||||
]
|
||||
|
||||
for src_name, dest_name in example_files:
|
||||
src_path = self.project_root / src_name
|
||||
if src_path.exists():
|
||||
dest_path = self.package_dir / dest_name
|
||||
shutil.copy2(src_path, dest_path)
|
||||
print(f"✅ 复制示例文件: {dest_name}")
|
||||
|
||||
# 创建启动脚本
|
||||
self.create_startup_script()
|
||||
|
||||
# 创建使用说明
|
||||
self.create_readme()
|
||||
|
||||
print(f"\n🎉 分发包创建完成: {self.package_dir}")
|
||||
return True
|
||||
|
||||
def create_startup_script(self):
|
||||
"""创建启动脚本"""
|
||||
bat_content = '''@echo off
|
||||
chcp 65001 >nul
|
||||
title 座位分配系统
|
||||
|
||||
echo ==========================================
|
||||
echo 座位分配系统 v1.0
|
||||
echo ==========================================
|
||||
echo.
|
||||
|
||||
:: 检查数据文件
|
||||
if not exist "人员信息.xlsx" (
|
||||
echo ❌ 缺少文件: 人员信息.xlsx
|
||||
echo.
|
||||
echo 请将 人员信息_示例.xlsx 重命名为 人员信息.xlsx
|
||||
echo 并按照格式填入您的数据
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if not exist "座位信息.xlsx" (
|
||||
echo ❌ 缺少文件: 座位信息.xlsx
|
||||
echo.
|
||||
echo 请将 座位信息_示例.xlsx 重命名为 座位信息.xlsx
|
||||
echo 并按照格式填入您的数据
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo ✅ 数据文件检查通过
|
||||
echo.
|
||||
echo 正在启动座位分配系统...
|
||||
echo.
|
||||
|
||||
:: 运行程序
|
||||
"座位分配系统.exe"
|
||||
|
||||
echo.
|
||||
echo 程序运行完毕
|
||||
pause
|
||||
'''
|
||||
|
||||
bat_file = self.package_dir / '运行座位分配系统.bat'
|
||||
with open(bat_file, 'w', encoding='gbk') as f:
|
||||
f.write(bat_content)
|
||||
|
||||
print(f"✅ 创建启动脚本: {bat_file.name}")
|
||||
|
||||
def create_readme(self):
|
||||
"""创建使用说明"""
|
||||
readme_content = f"""座位分配系统 使用说明
|
||||
|
||||
版本: v1.0
|
||||
构建时间: {time.strftime('%Y-%m-%d %H:%M:%S')}
|
||||
适用系统: Windows 7/10/11 (64位)
|
||||
|
||||
====================
|
||||
快速开始
|
||||
====================
|
||||
|
||||
1. 准备数据文件
|
||||
- 将 "人员信息_示例.xlsx" 重命名为 "人员信息.xlsx"
|
||||
- 将 "座位信息_示例.xlsx" 重命名为 "座位信息.xlsx"
|
||||
- 按照示例格式填入您的实际数据
|
||||
|
||||
2. 运行程序
|
||||
- 双击 "运行座位分配系统.bat" 启动程序
|
||||
- 或者直接双击 "座位分配系统.exe"
|
||||
|
||||
3. 查看结果
|
||||
- 座位信息_最终分配.xlsx (最终分配结果)
|
||||
- 最终座位分配日志.xlsx (详细分配记录)
|
||||
- seat_allocation_log.txt (运行日志)
|
||||
|
||||
====================
|
||||
数据文件格式要求
|
||||
====================
|
||||
|
||||
人员信息.xlsx 必需列:
|
||||
- 姓名: 人员姓名
|
||||
- 证件类型: 身份证/护照等
|
||||
- 证件号: 证件号码
|
||||
- 手机号: 联系电话
|
||||
- 备注: 连坐人数(留空表示单独坐)
|
||||
|
||||
座位信息.xlsx 必需列:
|
||||
- 区域: 座位区域
|
||||
- 楼层: 楼层信息
|
||||
- 排号: 排号
|
||||
- 座位号: 具体座位号
|
||||
|
||||
====================
|
||||
连坐规则说明
|
||||
====================
|
||||
|
||||
1. 单人坐位: 备注列留空
|
||||
2. 连坐组合: 第一人在备注列填写总人数,其他人备注留空
|
||||
例如: 张三(备注:3)、李四(备注:空)、王五(备注:空)
|
||||
表示这3人需要连坐
|
||||
|
||||
3. 支持1-10人连坐
|
||||
4. 系统自动寻找连续座位进行分配
|
||||
|
||||
====================
|
||||
常见问题
|
||||
====================
|
||||
|
||||
Q: 提示缺少依赖包怎么办?
|
||||
A: 程序会自动尝试安装,如果失败请确保网络连接正常
|
||||
|
||||
Q: 提示文件权限错误?
|
||||
A: 请确保程序有读写当前目录的权限
|
||||
|
||||
Q: 无法找到连续座位?
|
||||
A: 请检查座位信息是否完整,或调整连坐组大小
|
||||
|
||||
Q: Excel文件打不开?
|
||||
A: 请使用Microsoft Excel 2010或更高版本
|
||||
|
||||
====================
|
||||
技术支持
|
||||
====================
|
||||
|
||||
如果遇到问题,请检查以下内容:
|
||||
1. 数据文件格式是否正确
|
||||
2. 文件是否存在读写权限
|
||||
3. 系统是否为Windows 7以上版本
|
||||
4. 是否有足够的磁盘空间
|
||||
|
||||
详细错误信息请查看 seat_allocation_log.txt 文件
|
||||
"""
|
||||
|
||||
readme_file = self.package_dir / '使用说明.txt'
|
||||
with open(readme_file, 'w', encoding='utf-8') as f:
|
||||
f.write(readme_content)
|
||||
|
||||
print(f"✅ 创建使用说明: {readme_file.name}")
|
||||
|
||||
def build(self):
|
||||
"""执行完整构建流程"""
|
||||
print("开始Windows构建流程...\n")
|
||||
|
||||
# 1. 检查环境
|
||||
if not self.check_environment():
|
||||
return False
|
||||
|
||||
# 2. 安装依赖
|
||||
if not self.install_dependencies():
|
||||
return False
|
||||
|
||||
# 3. 清理构建目录
|
||||
self.clean_build_dirs()
|
||||
|
||||
# 4. 创建配置文件
|
||||
spec_file = self.create_spec_file()
|
||||
|
||||
# 5. 构建可执行文件
|
||||
success, exe_path = self.build_executable(spec_file)
|
||||
if not success:
|
||||
return False
|
||||
|
||||
# 6. 创建分发包
|
||||
if not self.create_distribution_package(exe_path):
|
||||
return False
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("构建完成!")
|
||||
print("=" * 60)
|
||||
print(f"✅ 分发包位置: {self.package_dir}")
|
||||
print(f"✅ 可执行文件: {exe_path}")
|
||||
print("\n使用方法:")
|
||||
print("1. 将整个分发包复制到目标电脑")
|
||||
print("2. 准备好人员信息.xlsx和座位信息.xlsx文件")
|
||||
print("3. 双击运行 '运行座位分配系统.bat'")
|
||||
|
||||
return True
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
builder = WindowsBuilder()
|
||||
|
||||
try:
|
||||
success = builder.build()
|
||||
if success:
|
||||
print("\n🎉 构建成功!")
|
||||
else:
|
||||
print("\n❌ 构建失败!")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n\n用户中断构建过程")
|
||||
except Exception as e:
|
||||
print(f"\n❌ 构建过程中出现未知错误: {e}")
|
||||
|
||||
finally:
|
||||
input("\n按Enter键退出...")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Reference in New Issue
Block a user