From 02341150a9bdb5b74786d2aea479427315860159 Mon Sep 17 00:00:00 2001 From: yovinchen Date: Wed, 2 Jul 2025 16:26:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8C=89=E7=85=A7=E6=89=8B?= =?UTF-8?q?=E6=9C=BA=E5=8F=B7=E6=8E=92=E5=BA=8F=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E9=80=89=E6=8B=A9=E6=96=87=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E8=AF=86=E5=88=AB=E6=96=87=E4=BB=B6=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=BA=A7=E4=BD=8D=E4=BF=A1=E6=81=AF=E8=A1=A8=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 人员信息.xlsx => 1.xlsx | Bin 座位信息.xlsx => 2.xlsx | Bin README.md | 52 ++++- Windows部署说明.md | 284 -------------------------- build_workflow.yml | 89 --------- cross_platform_build.py | 326 ------------------------------ log/seat_allocation_log.txt | 127 ------------ log/座位信息_最终分配.xlsx | Bin 5630 -> 0 bytes log/最终座位分配日志.xlsx | Bin 5371 -> 0 bytes seat_allocation.spec | 128 ------------ seat_allocation_log.txt | 85 -------- seat_allocation_system.py | 383 +++++++++++++++++++++++++++++++++--- simple_build.py | 232 ---------------------- 运行座位分配系统.bat | 116 ----------- 14 files changed, 394 insertions(+), 1428 deletions(-) rename 人员信息.xlsx => 1.xlsx (100%) rename 座位信息.xlsx => 2.xlsx (100%) delete mode 100644 Windows部署说明.md delete mode 100644 build_workflow.yml delete mode 100644 cross_platform_build.py delete mode 100644 log/seat_allocation_log.txt delete mode 100644 log/座位信息_最终分配.xlsx delete mode 100644 log/最终座位分配日志.xlsx delete mode 100644 seat_allocation.spec delete mode 100644 seat_allocation_log.txt delete mode 100644 simple_build.py delete mode 100644 运行座位分配系统.bat diff --git a/人员信息.xlsx b/1.xlsx similarity index 100% rename from 人员信息.xlsx rename to 1.xlsx diff --git a/座位信息.xlsx b/2.xlsx similarity index 100% rename from 座位信息.xlsx rename to 2.xlsx diff --git a/README.md b/README.md index f5a2588..4a9e248 100644 --- a/README.md +++ b/README.md @@ -5,22 +5,35 @@ ## 🎯 功能特点 - ✅ **智能分配**: 支持1-10人的各种连坐需求 -- ✅ **数据校验**: 完整的文件格式和逻辑校验 +- ✅ **智能识别**: 自动识别Excel文件类型,支持默认文件名和智能识别两种模式 +- ✅ **双重分组**: 支持备注分组和手机号分组两种模式 +- ✅ **数据校验**: 完整的文件格式和逻辑校验,支持重名+身份证号校验 - ✅ **不连续座位**: 自动处理座位号间隙 - ✅ **详细日志**: 完整的操作记录和结果验证 - ✅ **跨平台**: 支持Windows、macOS、Linux +- ✅ **智能覆盖**: 人员信息覆盖座位表对应列,分配备注单独存储在第13列 ## 📋 使用方法 ### 准备Excel文件 -1. **人员信息.xlsx** - 包含以下列: +1. **人员信息文件** - 包含以下列: - 姓名、证件类型、证件号、手机号、备注 - - 备注数字表示连坐人数(如:备注4表示当前行+后3行共4人连坐) + - **备注模式**: 备注数字表示连坐人数(如:备注4表示当前行+后3行共4人连坐) + - **手机号模式**: 相同手机号的人员自动识别为连坐组 -2. **座位信息.xlsx** - 包含以下列: +2. **座位信息文件** - 包含以下列: - 区域、楼层、排号、座位号 +### 文件识别方式 + +程序启动时会提供两种文件识别方式: +1. **默认文件名** - 读取固定文件名 `人员信息.xlsx` 和 `座位信息.xlsx` +2. **智能识别** - 自动分析目录中的Excel文件并识别类型 + - 根据列名特征自动判断文件类型 + - 支持任意文件名(如 `1.xlsx`、`2.xlsx`) + - 提供手动选择功能作为备选 + ### 运行程序 #### Python环境运行 @@ -41,12 +54,28 @@ python simple_build.py python cross_platform_build.py ``` +### 选择文件识别模式 + +程序运行时首先选择文件识别模式: +1. **默认文件名** - 读取 `人员信息.xlsx` 和 `座位信息.xlsx` +2. **智能识别** - 自动识别目录中的Excel文件 + +### 选择分组方式 + +然后选择连坐分组方式: +1. **备注分组** - 根据备注数字识别连坐组(默认) +2. **手机号分组** - 根据相同手机号识别连坐组 + ### 查看结果 程序运行后会生成: -- `座位信息_最终分配.xlsx` - 最终分配结果 -- `最终座位分配日志.xlsx` - 详细分配记录 -- `seat_allocation_log.txt` - 完整运行日志 +- `log/座位信息_最终分配.xlsx` - 最终分配结果 + - 第1-5列:座位基本信息(保持不变) + - 第6-10列:人员信息(覆盖原座位表数据) + - 第11-12列:原座位表其他列(保持不变) + - 第13列:分配备注(新增列) +- `log/最终座位分配日志.xlsx` - 详细分配记录 +- `log/seat_allocation_log.txt` - 完整运行日志 ## 🔧 构建选项 @@ -117,9 +146,12 @@ A区通道 | 一层 | 1排 | 3号 ## ⚠️ 注意事项 1. **备注逻辑**: 备注数字表示连坐人数,只有组长填写备注,成员留空 -2. **证件号格式**: 支持包含X的身份证号,自动处理为字符串格式 -3. **文字清理**: 自动清除姓名等字段的多余空格 -4. **座位连续性**: 支持不连续座位号,算法会自动寻找合适的连续段 +2. **手机号逻辑**: 相同手机号的人员会被识别为连坐组 +3. **重名处理**: 支持重名人员,通过姓名+身份证号组合进行唯一性校验 +4. **证件号格式**: 支持包含X的身份证号,自动处理为字符串格式 +5. **文字清理**: 自动清除姓名等字段的多余空格 +6. **座位连续性**: 支持不连续座位号,算法会自动寻找合适的连续段 +7. **智能覆盖**: 人员信息覆盖座位表对应列,分配备注单独存储 ## 🔍 故障排除 diff --git a/Windows部署说明.md b/Windows部署说明.md deleted file mode 100644 index 3c8f37f..0000000 --- a/Windows部署说明.md +++ /dev/null @@ -1,284 +0,0 @@ -# 座位分配系统 - 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 -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位) \ No newline at end of file diff --git a/build_workflow.yml b/build_workflow.yml deleted file mode 100644 index b2cfde3..0000000 --- a/build_workflow.yml +++ /dev/null @@ -1,89 +0,0 @@ -# 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 }} diff --git a/cross_platform_build.py b/cross_platform_build.py deleted file mode 100644 index 5a660a5..0000000 --- a/cross_platform_build.py +++ /dev/null @@ -1,326 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -跨平台构建脚本 -在macOS上构建Windows x86/x64版本的exe文件 -使用Wine和PyInstaller实现跨平台编译 -""" - -import os -import sys -import subprocess -import platform -import shutil -from pathlib import Path - -def check_dependencies(): - """检查必要的依赖""" - print("检查构建依赖...") - - # 检查是否在macOS上 - if platform.system() != 'Darwin': - print(f"当前系统: {platform.system()}") - print("此脚本专为macOS设计,用于构建Windows版本") - return False - - # 检查Python包 - required_packages = ['pandas', 'openpyxl', 'pyinstaller'] - missing_packages = [] - - for package in required_packages: - try: - __import__(package) - print(f"✅ {package} 已安装") - except ImportError: - missing_packages.append(package) - print(f"❌ {package} 未安装") - - if missing_packages: - print(f"\n安装缺失的包...") - for package in missing_packages: - try: - subprocess.check_call([sys.executable, '-m', 'pip', 'install', package]) - print(f"✅ {package} 安装成功") - except subprocess.CalledProcessError: - print(f"❌ {package} 安装失败") - return False - - return True - -def install_wine(): - """安装Wine(如果需要)""" - print("\n检查Wine环境...") - - # 检查是否已安装Wine - try: - result = subprocess.run(['wine', '--version'], capture_output=True, text=True) - if result.returncode == 0: - print(f"✅ Wine已安装: {result.stdout.strip()}") - return True - except FileNotFoundError: - pass - - print("Wine未安装,开始安装...") - print("请按照以下步骤手动安装Wine:") - print("1. 安装Homebrew (如果未安装): /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"") - print("2. 安装Wine: brew install --cask wine-stable") - print("3. 配置Wine: winecfg") - - response = input("是否已完成Wine安装? (y/N): ") - return response.lower() == 'y' - -def setup_wine_python(): - """在Wine中设置Python环境""" - print("\n设置Wine Python环境...") - - # 检查Wine中是否已安装Python - try: - result = subprocess.run(['wine', 'python', '--version'], capture_output=True, text=True) - if result.returncode == 0: - print(f"✅ Wine Python已安装: {result.stdout.strip()}") - return True - except: - pass - - print("需要在Wine中安装Python...") - print("请按照以下步骤:") - print("1. 下载Windows版Python: https://www.python.org/downloads/windows/") - print("2. 使用Wine安装: wine python-3.10.x-amd64.exe") - print("3. 安装pip包: wine python -m pip install pandas openpyxl pyinstaller") - - response = input("是否已完成Wine Python安装? (y/N): ") - return response.lower() == 'y' - -def create_build_spec(target_arch='x64'): - """创建构建规格文件""" - exe_name = f"座位分配系统_{target_arch}" - - spec_content = f'''# -*- 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' - ], - hookspath=[], - hooksconfig={{}}, - runtime_hooks=[], - excludes=[ - 'matplotlib', - 'scipy', - 'IPython', - 'jupyter', - 'notebook', - 'tkinter' - ], - 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='{exe_name}', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=True, - upx_exclude=[], - runtime_tmpdir=None, - console=True, - disable_windowed_traceback=False, - argv_emulation=False, - target_arch=None, - codesign_identity=None, - entitlements_file=None, - icon=None, -) -''' - - spec_file = f'{exe_name}.spec' - with open(spec_file, 'w', encoding='utf-8') as f: - f.write(spec_content) - - return spec_file, exe_name - -def build_with_docker(): - """使用Docker构建Windows版本""" - print("\n使用Docker构建Windows版本...") - - # 创建Dockerfile - dockerfile_content = '''FROM python:3.10-windowsservercore - -# 设置工作目录 -WORKDIR /app - -# 复制文件 -COPY requirements.txt . -COPY seat_allocation_system.py . - -# 安装依赖 -RUN pip install -r requirements.txt - -# 构建exe -RUN pyinstaller --onefile --console --name "座位分配系统_x64" seat_allocation_system.py - -# 输出目录 -VOLUME ["/app/dist"] -''' - - with open('Dockerfile.windows', 'w') as f: - f.write(dockerfile_content) - - print("Docker方法需要Docker Desktop和Windows容器支持") - print("这是一个高级选项,建议使用其他方法") - return False - -def build_native_macos(): - """在macOS上直接构建(生成macOS版本)""" - print("\n在macOS上构建本地版本...") - - # 清理之前的构建 - if os.path.exists('dist'): - shutil.rmtree('dist') - if os.path.exists('build'): - shutil.rmtree('build') - - # 构建命令 - cmd = [ - sys.executable, '-m', 'PyInstaller', - '--onefile', - '--console', - '--clean', - '--name', '座位分配系统_macos', - 'seat_allocation_system.py' - ] - - try: - print(f"执行命令: {' '.join(cmd)}") - result = subprocess.run(cmd, capture_output=True, text=True) - - if result.returncode == 0: - print("✅ macOS版本构建成功!") - - # 检查生成的文件 - app_path = Path('dist') / '座位分配系统_macos' - if app_path.exists(): - file_size = app_path.stat().st_size / (1024 * 1024) # MB - print(f"生成文件: {app_path}") - print(f"文件大小: {file_size:.1f} MB") - return True, app_path - else: - print("❌ 构建失败!") - print("错误输出:") - print(result.stderr) - return False, None - - except Exception as e: - print(f"❌ 构建过程中出现错误: {e}") - return False, None - -def create_cross_compile_script(): - """创建跨编译脚本""" - script_content = '''#!/bin/bash -# Windows交叉编译脚本 - -echo "座位分配系统 - Windows交叉编译" -echo "================================" - -# 检查是否安装了mingw-w64 -if ! command -v x86_64-w64-mingw32-gcc &> /dev/null; then - echo "安装mingw-w64..." - brew install mingw-w64 -fi - -# 设置交叉编译环境 -export CC=x86_64-w64-mingw32-gcc -export CXX=x86_64-w64-mingw32-g++ - -# 构建Windows版本 -echo "开始构建Windows x64版本..." -python -m PyInstaller \\ - --onefile \\ - --console \\ - --clean \\ - --name "座位分配系统_x64" \\ - --target-arch x86_64 \\ - seat_allocation_system.py - -echo "构建完成!" -''' - - with open('cross_compile.sh', 'w') as f: - f.write(script_content) - - # 设置执行权限 - os.chmod('cross_compile.sh', 0o755) - print("✅ 已创建交叉编译脚本: cross_compile.sh") - -def main(): - """主函数""" - print("座位分配系统 - 跨平台构建工具") - print("=" * 50) - print("在macOS上构建Windows版本") - - # 检查依赖 - if not check_dependencies(): - return - - print("\n选择构建方法:") - print("1. 构建macOS版本(推荐)") - print("2. 使用Wine构建Windows版本(复杂)") - print("3. 创建交叉编译脚本(实验性)") - print("4. 生成Docker构建文件(高级)") - - choice = input("\n请选择 (1-4): ").strip() - - if choice == '1': - print("\n构建macOS版本...") - success, app_path = build_native_macos() - if success: - print(f"\n🎉 构建完成!") - print(f"生成文件: {app_path}") - print("\n注意: 这是macOS版本,不能在Windows上运行") - print("如需Windows版本,请在Windows系统上运行构建脚本") - - elif choice == '2': - print("\n使用Wine构建Windows版本...") - if install_wine() and setup_wine_python(): - print("Wine环境已准备就绪") - print("请手动在Wine中运行: wine python windows_build.py") - else: - print("Wine环境设置失败") - - elif choice == '3': - print("\n创建交叉编译脚本...") - create_cross_compile_script() - print("请运行: ./cross_compile.sh") - - elif choice == '4': - print("\n生成Docker构建文件...") - build_with_docker() - - else: - print("无效选择") - -if __name__ == "__main__": - main() diff --git a/log/seat_allocation_log.txt b/log/seat_allocation_log.txt deleted file mode 100644 index 7cf755d..0000000 --- a/log/seat_allocation_log.txt +++ /dev/null @@ -1,127 +0,0 @@ -[2025-07-01 15:41:09] ============================================================ -[2025-07-01 15:41:09] 座位分配系统 - 文件校验 -[2025-07-01 15:41:09] ============================================================ -[2025-07-01 15:41:09] === 开始加载数据 === -[2025-07-01 15:41:09] 正在读取人员信息文件: 人员信息.xlsx -[2025-07-01 15:41:09] 正在读取座位信息文件: 座位信息.xlsx -[2025-07-01 15:41:09] 开始过滤座位数据... -[2025-07-01 15:41:09] 原始数据行数: 17 -[2025-07-01 15:41:09] 过滤后数据行数: 6 -[2025-07-01 15:41:09] 移除无效行数: 11 -[2025-07-01 15:41:09] ✅ 已过滤掉 11 行无效数据(空行、示例数据等) -[2025-07-01 15:41:09] 有效座位区域: 西北门入口场地A5区 -[2025-07-01 15:41:09] 有效座位楼层: 场地 -[2025-07-01 15:41:09] 清理文字数据中的空格... -[2025-07-01 15:41:09] ✅ 文字数据清理完成 -[2025-07-01 15:41:09] ✅ 文件加载成功 -[2025-07-01 15:41:09] 人员信息: 6 行 × 6 列 -[2025-07-01 15:41:09] 座位信息: 6 行 × 12 列 -[2025-07-01 15:41:09] -=== 人员信息结构校验 === -[2025-07-01 15:41:09] ✅ 所有必需列都存在 -[2025-07-01 15:41:09] -数据完整性检查: -[2025-07-01 15:41:09] ✅ 姓名 列数据完整 -[2025-07-01 15:41:09] ✅ 证件类型 列数据完整 -[2025-07-01 15:41:09] ✅ 证件号 列数据完整 -[2025-07-01 15:41:09] ✅ 手机号 列数据完整 -[2025-07-01 15:41:09] ✅ 姓名无重复 -[2025-07-01 15:41:09] -=== 连坐组校验 === -[2025-07-01 15:41:09] ✅ 第 1 组: 叶一帆 (单独) -[2025-07-01 15:41:09] ✅ 第 2 组: 刘泽 (单独) -[2025-07-01 15:41:09] ✅ 第 3 组: 黄锡恩 (单独) -[2025-07-01 15:41:09] ✅ 第 4 组: 胡中, 丁逸夫 (2人连坐) -[2025-07-01 15:41:09] ✅ 第 5 组: 沈佳琰 (单独) -[2025-07-01 15:41:09] -=== 座位信息结构校验 === -[2025-07-01 15:41:09] ✅ 所有必需列都存在 -[2025-07-01 15:41:09] ✅ 区域 列数据完整 -[2025-07-01 15:41:09] ✅ 楼层 列数据完整 -[2025-07-01 15:41:09] ✅ 排号 列数据完整 -[2025-07-01 15:41:09] ✅ 座位号 列数据完整 -[2025-07-01 15:41:09] -座位结构分析: -[2025-07-01 15:41:09] -座位结构分析: -[2025-07-01 15:41:09] ✅ 西北门入口场地A5区-场地-19排: 6 个座位完全连续 (1-6) -[2025-07-01 15:41:09] -=== 容量和可行性校验 === -[2025-07-01 15:41:09] 总人数: 6 -[2025-07-01 15:41:09] 总座位数: 6 -[2025-07-01 15:41:09] ✅ 座位充足: 剩余 0 个座位 -[2025-07-01 15:41:09] -连坐组需求分析: -[2025-07-01 15:41:09] 最大连坐组: 2 人 -[2025-07-01 15:41:09] -连续座位可行性分析: -[2025-07-01 15:41:09] 西北门入口场地A5区-场地-19排: 最大连续 6 个座位 -[2025-07-01 15:41:09] -全场最大连续座位: 6 个 -[2025-07-01 15:41:09] ✅ 可以容纳最大连坐组 -[2025-07-01 15:41:09] 可容纳最大连坐组的排数: 1 个 -[2025-07-01 15:41:09] -连坐组分布: -[2025-07-01 15:41:09] 单人组: 4 个 -[2025-07-01 15:41:09] 2人连坐组: 1 个 -[2025-07-01 15:41:09] -============================================================ -[2025-07-01 15:41:09] 校验结果总结 -[2025-07-01 15:41:09] ============================================================ -[2025-07-01 15:41:09] 人员信息结构: ✅ 通过 -[2025-07-01 15:41:09] 连坐组完整性: ✅ 通过 -[2025-07-01 15:41:09] 座位信息结构: ✅ 通过 -[2025-07-01 15:41:09] 容量可行性: ✅ 通过 -[2025-07-01 15:41:09] -总体校验结果: ✅ 全部通过 -[2025-07-01 15:41:09] -🎉 文件校验通过,可以进行座位分配! -[2025-07-01 15:41:19] -============================================================ -[2025-07-01 15:41:19] 开始座位分配 -[2025-07-01 15:41:19] ============================================================ -[2025-07-01 15:41:19] -=== 人员连坐需求分析 === -[2025-07-01 15:41:19] 总共识别出 5 个座位组: -[2025-07-01 15:41:19] 单人组: 4 个 -[2025-07-01 15:41:19] 2人连坐组: 1 个 -[2025-07-01 15:41:19] -=== 高级座位结构分析 === -[2025-07-01 15:41:19] ✅ 西北门入口场地A5区-场地-19排: 6 个座位完全连续 -[2025-07-01 15:41:19] -=== 开始智能座位分配 === -[2025-07-01 15:41:19] 需要分配 5 个组 -[2025-07-01 15:41:19] -处理第 1 组: 胡中 (group, 2 人) -[2025-07-01 15:41:19] 分配到 西北门入口场地A5区-场地-19排 (连续座位: 1-2) -[2025-07-01 15:41:19] 胡中 -> 1号 -[2025-07-01 15:41:19] 丁逸夫 -> 2号 -[2025-07-01 15:41:19] -处理第 2 组: 叶一帆 (single, 1 人) -[2025-07-01 15:41:19] 分配到 西北门入口场地A5区-场地-19排: 叶一帆 -> 3号 -[2025-07-01 15:41:19] -处理第 3 组: 刘泽 (single, 1 人) -[2025-07-01 15:41:19] 分配到 西北门入口场地A5区-场地-19排: 刘泽 -> 4号 -[2025-07-01 15:41:19] -处理第 4 组: 黄锡恩 (single, 1 人) -[2025-07-01 15:41:19] 分配到 西北门入口场地A5区-场地-19排: 黄锡恩 -> 5号 -[2025-07-01 15:41:19] -处理第 5 组: 沈佳琰 (single, 1 人) -[2025-07-01 15:41:19] 分配到 西北门入口场地A5区-场地-19排: 沈佳琰 -> 6号 -[2025-07-01 15:41:19] -座位分配结果已保存到: log/座位信息_最终分配.xlsx -[2025-07-01 15:41:19] 分配日志已保存到: log/最终座位分配日志.xlsx -[2025-07-01 15:41:19] -=== 分配统计 === -[2025-07-01 15:41:19] 总共分配了 6 个座位 -[2025-07-01 15:41:19] -按组大小统计: -[2025-07-01 15:41:19] 单人组: 4 个组, 4 人 -[2025-07-01 15:41:19] 2人连坐组: 1 个组, 2 人 -[2025-07-01 15:41:19] -=== 连续性验证 === -[2025-07-01 15:41:19] ✅ 组 1 (胡中): 2人连坐,座位连续 [1, 2] -[2025-07-01 15:41:19] -连续性检查结果: 1/1 个多人组座位连续 (100.0%) -[2025-07-01 15:41:19] -🎉 座位分配完成! \ No newline at end of file diff --git a/log/座位信息_最终分配.xlsx b/log/座位信息_最终分配.xlsx deleted file mode 100644 index d505a1282c0f080ecc042d12bf54f539d823d625..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5630 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%0D*{8)-fYTr>bc@eTk$@p}XD zfH>Q^ScAc?E)W0u`D+)+OkLEN=b;FNFb`tH{e&%QQR1-OqgIp2ap=o+n-6FDM4jqr zRUyehpjS;-i3WmVnoodmLaU$fbdOAeTcU(>q0twrWU;oQUQ2Mqx=Q6#ujK&bz8s7- zcK;IGp!{C2jO|rT1oZ@67p?O}q6kZ@vR5jIbeXZgBqYv)qd~2(NT_ggu<>r}2=G}K zm#q5op|4LJ{4= z9vxJ2JzOAad%(cD#n}?_t;b3>f?02#R{Mth`Wgf-FTk49C9N8jwD) zUzgNf4Py`iHf+mnbSAB6R+m@_fQ22!v2?A87LMi0)}J@{cRkRW$=+&e`Q{PdI|)T0 z{;_56XIF6+(z0Nc3Ag_Nb)eHIS}0OtO>&Nikdu)^aHq2IVWSSr9mm)D2G#l+I$WST zXi=09-1lDm+@X@X??>_$ZK!|`3)cRH9uth=v&K6VZw?~&9 zF$rVA4_DeED8cg%#vY|YCrxM}V}$g~XplR4aug!;)DAIW1m|0WKNf#})sJud-?*@L z1U+gs7K-i1mdBRmr1Oxo(3Z!xJ}`72EyJ5W!-KtZbDe62iMl|1Y!xd)mB8Pthzt;C zc1OYCHu$bSUSVwdQ9EO^K%%x;j2%LS32pNRB=zM=~j zZhtGf!T6_tz9U}ayh8;59Pj`Dg5UmearLqXyZmas7WL+1(|L%l$-1$U)U~vWWC|XQ zt0d3a!WP3?)69aHO^bMoE!$f8Ye^FJ?kplIbD&4m*$twW;`R9(uW7cph1uSRJ=o9K zl?2aL?ADuiVNJLYDA|>m-$`-LCTQ6#xffSpS=-#i!Pf)T5VRBj;IkQOX{E6L;gnnb z<4B``_hYV!oPZX!qm8!%4;J~@Z8vI1CHyV)nN4H}6uDZtU zO+7z%5)7s1eK6l{2g!LCTD<=CQI^~jQ>tZG&OK%5Mn1)GH-<<(h&WOrQXalRNhp#*u_b6SX=`V(VpDWDj5uSV*8HGvlnr5lgM7$N4$y; zV}lPRAQ#lx??T*(CW;pS+>D+nX=_#9`$S?$(f88?^R2@-y@ukX%!KP~OyHR;dW-4UE@#-VC^51sHTXdfyVrJUut%0gH zSy^1=grFREYL|JKeJ@Y9@vNReDd3|WyII!DJc9=Us#09Jpt#Yq86wUvC(Qj^U5-rK?VFR)B2w{-woD#a#Q3y44hy8>;+Az0ZYUpk zkS9uZWTJ$>t@~^1GlxLzewjBWZtT~YQr;gnh&AdMq^!1U@+LqTn@H9NZs<{y(w)5S zSW(WZ%&xW;!rC`IHPB*`5l$$YCyRI*(fx zloz^K4w-qOcv>$TeEjso>7yLJs5@L)x!g~3`Ig6b;wj)8a_Qq7uxbVWT(2$co4+38{ZmE!yX%dmNK$_w38wr_?r$Oeo#MYlRTD3MCzuC6q?~vYKv6WA zi(1HCLPj1QbO8*Mt1Rx^r|JMG(KPZrg{QQAx3qc)iu4iHo)#rOv1SN zA zgH59i<4$|TqYlFawm2BuuJPqZje>w7V&Fqeo7Yu4iT>U&$*^Y&`}z$6aK-vkhLzLZ zwOdK1hsr>ykO@vB8>nBWZzEZVqbu0a)l}EZ3GDLhmx@Xg;lEVWYYO}7X3H<+B(=*O z&9T>x2km~A|0UZT;tF{^|4}8Uk|0?%zZdb{<%+qu&H{Z{#7bPxOO})_MCx-uqCqHj z7NeVz2JuZ{X87Y8XRNhX4ZcJVJW(|<&L}UuYXS|wae?79kbIohK@x-Es&~AVR!L+v?8T9o>1@~TjGtWk!B zD6Jat-5f}_a}cqrD$zIvy_f+RT#92oWT2zC=T}Q3j%INUN*j|7xWL&ObpNeP`<>#b zewny_W8n>`<^C)ybm=9*rJj)HIb(tQA$m{6Fx`nqHtV$!r59oD^?}b+IV`bPlOTLm zyj&95h@zm9qW$+l6_U`uJ^@IE|Nq$PHv0CA=r2QEs;r|A~TPf~>{JW&CL_ZbNU^?LSZ+WN-hsDt;Sy zyAJ*V-b0o}= 3: # 至少包含3个座位强特征 + analysis['type'] = 'seat' + analysis['score'] = seat_strong_score * 10 # 给予高权重 + # 如果有人员强特征且列数较少,识别为人员文件 + elif personnel_strong_score > 0 and len(df_sample.columns) <= 8: + analysis['type'] = 'personnel' + analysis['score'] = personnel_strong_score * 10 + else: + # 使用原有的弱特征判断 + personnel_keywords = ['姓名', '证件', '手机', 'name', 'id', 'phone'] + personnel_score = sum(1 for keyword in personnel_keywords if keyword in columns_str) + + seat_keywords = ['区域', '楼层', '排号', '座位', 'area', 'floor', 'row', 'seat'] + seat_score = sum(1 for keyword in seat_keywords if keyword in columns_str) + + # 结合列数进行判断 + if len(df_sample.columns) <= 8 and personnel_score > 0: + analysis['type'] = 'personnel' + analysis['score'] = personnel_score + elif len(df_sample.columns) > 8 and seat_score > 0: + analysis['type'] = 'seat' + analysis['score'] = seat_score + elif personnel_score > seat_score: + analysis['type'] = 'personnel' + analysis['score'] = personnel_score + elif seat_score > personnel_score: + analysis['type'] = 'seat' + analysis['score'] = seat_score + + file_analysis.append(analysis) + + self.logger.log(f" 📄 {file_path.name}: {total_rows}行 × {len(df_sample.columns)}列") + self.logger.log(f" 列名: {', '.join(str(col) for col in df_sample.columns[:5])}{'...' if len(df_sample.columns) > 5 else ''}") + self.logger.log(f" 推测类型: {analysis['type']} (得分: {analysis['score']})") + + except Exception as e: + self.logger.log(f" ❌ {file_path.name}: 读取失败 - {e}") + + # 自动匹配最佳文件 + personnel_files = [f for f in file_analysis if f['type'] == 'personnel'] + seat_files = [f for f in file_analysis if f['type'] == 'seat'] + + personnel_file = None + seat_file = None + + if personnel_files: + personnel_file = max(personnel_files, key=lambda x: x['score'])['path'] + self.logger.log(f"\n🎯 自动识别人员信息文件: {personnel_file.name}") + + if seat_files: + seat_file = max(seat_files, key=lambda x: x['score'])['path'] + self.logger.log(f"🎯 自动识别座位信息文件: {seat_file.name}") + + # 如果自动识别不完整,提供手动选择 + if not personnel_file or not seat_file: + self.logger.log("\n⚠️ 自动识别不完整,请手动选择:") + personnel_file, seat_file = self.manual_select_files(file_analysis) + + return personnel_file, seat_file + + def manual_select_files(self, file_analysis): + """手动选择文件""" + self.logger.log("\n=== 手动选择文件 ===") + + print("\n可用的Excel文件:") + for i, analysis in enumerate(file_analysis): + print(f"{i+1}. {analysis['name']} ({analysis['rows']}行 × {analysis['cols']}列)") + print(f" 列名: {', '.join(str(col) for col in analysis['columns'][:3])}...") + + personnel_file = None + seat_file = None + + # 选择人员信息文件 + while not personnel_file: + try: + choice = input(f"\n请选择人员信息文件 (1-{len(file_analysis)}): ").strip() + idx = int(choice) - 1 + if 0 <= idx < len(file_analysis): + personnel_file = file_analysis[idx]['path'] + self.logger.log(f"✅ 选择人员信息文件: {personnel_file.name}") + else: + print("请输入有效的数字") + except (ValueError, KeyboardInterrupt): + print("请输入有效的数字") + + # 选择座位信息文件 + while not seat_file: + try: + choice = input(f"\n请选择座位信息文件 (1-{len(file_analysis)}): ").strip() + idx = int(choice) - 1 + if 0 <= idx < len(file_analysis): + if file_analysis[idx]['path'] == personnel_file: + print("不能选择相同的文件,请重新选择") + continue + seat_file = file_analysis[idx]['path'] + self.logger.log(f"✅ 选择座位信息文件: {seat_file.name}") + else: + print("请输入有效的数字") + except (ValueError, KeyboardInterrupt): + print("请输入有效的数字") + + return personnel_file, seat_file + def set_data_files(self, personnel_file, seat_file): """设置数据文件路径""" self.personnel_file = personnel_file self.seat_file = seat_file + + def identify_and_set_files(self): + """识别并设置数据文件""" + file_mode = self.choose_file_mode() + + if file_mode == 'default': + # 默认文件名模式 + personnel_file = Path('人员信息.xlsx') + seat_file = Path('座位信息.xlsx') + + if not personnel_file.exists(): + self.logger.log(f"❌ 错误: {personnel_file} 文件不存在") + return False + + if not seat_file.exists(): + self.logger.log(f"❌ 错误: {seat_file} 文件不存在") + return False + + else: + # 智能识别模式 + personnel_file, seat_file = self.smart_identify_files() + if not personnel_file or not seat_file: + self.logger.log("❌ 文件识别失败") + return False + + self.set_data_files(personnel_file, seat_file) + return True def load_data(self): """加载人员信息和座位信息数据""" @@ -382,23 +577,23 @@ class SeatAllocationSystem: def validate_personnel_structure(self): """校验人员信息文件结构""" self.logger.log("\n=== 人员信息结构校验 ===") - + required_columns = ['姓名', '证件类型', '证件号', '手机号', '备注'] validation_results = [] - + # 检查必需列 missing_columns = [] for col in required_columns: if col not in self.personnel_df.columns: missing_columns.append(col) - + if missing_columns: self.logger.log(f"❌ 缺少必需列: {missing_columns}") validation_results.append(False) else: self.logger.log("✅ 所有必需列都存在") validation_results.append(True) - + # 检查数据完整性 self.logger.log("\n数据完整性检查:") for col in ['姓名', '证件类型', '证件号', '手机号']: @@ -410,16 +605,36 @@ class SeatAllocationSystem: else: self.logger.log(f"✅ {col} 列数据完整") validation_results.append(True) - - # 检查重复姓名 - duplicate_names = self.personnel_df[self.personnel_df['姓名'].duplicated()] - if not duplicate_names.empty: - self.logger.log(f"⚠️ 发现重复姓名: {duplicate_names['姓名'].tolist()}") - validation_results.append(False) + + # 检查重复人员(姓名+身份证号组合) + self.logger.log("\n重复人员检查:") + if '姓名' in self.personnel_df.columns and '证件号' in self.personnel_df.columns: + # 创建姓名+证件号的组合标识 + self.personnel_df['人员标识'] = self.personnel_df['姓名'].astype(str) + '_' + self.personnel_df['证件号'].astype(str) + duplicate_persons = self.personnel_df[self.personnel_df['人员标识'].duplicated()] + + if not duplicate_persons.empty: + self.logger.log(f"⚠️ 发现重复人员:") + for _, person in duplicate_persons.iterrows(): + self.logger.log(f" {person['姓名']} (证件号: {person['证件号']})") + validation_results.append(False) + else: + self.logger.log("✅ 无重复人员(姓名+证件号组合检查)") + validation_results.append(True) + + # 单独检查重名情况(仅提示,不影响校验结果) + duplicate_names = self.personnel_df[self.personnel_df['姓名'].duplicated(keep=False)] + if not duplicate_names.empty: + self.logger.log(f"📝 发现重名人员(但证件号不同,允许通过):") + name_groups = duplicate_names.groupby('姓名') + for name, group in name_groups: + self.logger.log(f" 姓名: {name}") + for _, person in group.iterrows(): + self.logger.log(f" 证件号: {person['证件号']}") else: - self.logger.log("✅ 姓名无重复") - validation_results.append(True) - + self.logger.log("❌ 缺少姓名或证件号列,无法进行重复检查") + validation_results.append(False) + return all(validation_results) def validate_seating_groups(self): @@ -693,10 +908,73 @@ class SeatAllocationSystem: return True - def analyze_seating_requirements(self): + def analyze_seating_requirements(self, use_phone_grouping=False): """分析人员连坐需求""" self.logger.log("\n=== 人员连坐需求分析 ===") + if use_phone_grouping: + self.logger.log("🔍 使用手机号分组模式") + return self.analyze_seating_by_phone() + else: + self.logger.log("🔍 使用备注分组模式") + return self.analyze_seating_by_remark() + + def analyze_seating_by_phone(self): + """基于手机号分析连坐需求""" + self.logger.log("根据相同手机号识别连坐组...") + + # 按手机号分组 + phone_groups = self.personnel_df.groupby('手机号') + self.seating_groups = [] + + for phone, group in phone_groups: + group_members = [row for _, row in group.iterrows()] + group_size = len(group_members) + + if group_size == 1: + # 单人组 + self.seating_groups.append({ + 'type': 'single', + 'size': 1, + 'members': group_members, + 'leader': group_members[0]['姓名'], + 'grouping_method': 'phone' + }) + self.logger.log(f"📱 单人: {group_members[0]['姓名']} (手机号: {phone})") + else: + # 连坐组 + leader_name = group_members[0]['姓名'] + member_names = [member['姓名'] for member in group_members] + + self.seating_groups.append({ + 'type': 'group', + 'size': group_size, + 'members': group_members, + 'leader': leader_name, + 'grouping_method': 'phone' + }) + self.logger.log(f"📱 连坐组: {', '.join(member_names)} (手机号: {phone}, {group_size}人)") + + # 统计 + size_stats = {} + for group in self.seating_groups: + size = group['size'] + size_stats[size] = size_stats.get(size, 0) + 1 + + self.logger.log(f"\n基于手机号识别出 {len(self.seating_groups)} 个座位组:") + for size in sorted(size_stats.keys()): + count = size_stats[size] + if size == 1: + self.logger.log(f" 单人组: {count} 个") + else: + self.logger.log(f" {size}人连坐组: {count} 个") + + return True + + def analyze_seating_by_remark(self): + """基于备注分析连坐需求""" + self.logger.log("根据备注数字识别连坐组...") + self.seating_groups = [] i = 0 @@ -710,7 +988,8 @@ class SeatAllocationSystem: 'type': 'single', 'size': 1, 'members': [person], - 'leader': person['姓名'] + 'leader': person['姓名'], + 'grouping_method': 'remark' }) i += 1 else: @@ -727,7 +1006,8 @@ class SeatAllocationSystem: 'type': 'group' if group_size > 1 else 'single', 'size': len(group_members), 'members': group_members, - 'leader': person['姓名'] + 'leader': person['姓名'], + 'grouping_method': 'remark' }) i += group_size @@ -738,7 +1018,7 @@ class SeatAllocationSystem: size = group['size'] size_stats[size] = size_stats.get(size, 0) + 1 - self.logger.log(f"总共识别出 {len(self.seating_groups)} 个座位组:") + self.logger.log(f"\n基于备注识别出 {len(self.seating_groups)} 个座位组:") for size in sorted(size_stats.keys()): count = size_stats[size] if size == 1: @@ -861,13 +1141,14 @@ class SeatAllocationSystem: person_info = seating_group['members'][0] seat_index = seat_info['index'] - # 更新座位信息,确保数据类型正确 + # 覆盖座位表中的人员信息列 seat_df_copy.loc[seat_index, '姓名'] = str(person_info['姓名']).strip() seat_df_copy.loc[seat_index, '证件类型'] = str(person_info['证件类型']).strip() seat_df_copy.loc[seat_index, '证件号'] = str(person_info['证件号']).strip() seat_df_copy.loc[seat_index, '手机国家号'] = person_info.get('Unnamed: 3', 86) seat_df_copy.loc[seat_index, '手机号'] = str(person_info['手机号']).strip() - seat_df_copy.loc[seat_index, '签发地/国籍'] = str(person_info.get('备注', '')).strip() + # 只有分配备注放在第13列 + seat_df_copy.loc[seat_index, '分配备注'] = str(person_info.get('备注', '')).strip() assignment_log.append({ '组号': group_idx + 1, @@ -945,7 +1226,8 @@ class SeatAllocationSystem: seat_df_copy.loc[seat_index, '证件号'] = str(person_info['证件号']).strip() seat_df_copy.loc[seat_index, '手机国家号'] = person_info.get('Unnamed: 3', 86) seat_df_copy.loc[seat_index, '手机号'] = str(person_info['手机号']).strip() - seat_df_copy.loc[seat_index, '签发地/国籍'] = str(person_info.get('备注', '')).strip() + # 只有分配备注放在第13列 + seat_df_copy.loc[seat_index, '分配备注'] = str(person_info.get('备注', '')).strip() assignment_log.append({ '组号': group_idx + 1, @@ -990,6 +1272,15 @@ class SeatAllocationSystem: output_file = self.logger.get_log_path('座位信息_最终分配.xlsx') seat_df_result.to_excel(output_file, index=False) self.logger.log(f"\n座位分配结果已保存到: {output_file}") + self.logger.log(f"📋 人员信息已覆盖到座位表对应列:") + self.logger.log(f" 第6列: 姓名") + self.logger.log(f" 第7列: 证件类型") + self.logger.log(f" 第8列: 证件号") + self.logger.log(f" 第9列: 手机国家号") + self.logger.log(f" 第10列: 手机号") + self.logger.log(f"📝 分配备注信息:") + self.logger.log(f" 第13列: 分配备注(新增列,不覆盖原数据)") + self.logger.log(f"💡 座位基本信息(第1-5列)保持不变") # 保存分配日志 if assignment_log: @@ -1067,6 +1358,10 @@ class SeatAllocationSystem: self.logger.log("座位分配系统 - 文件校验") self.logger.log("=" * 60) + # 识别并设置数据文件 + if not self.identify_and_set_files(): + return False + # 加载数据 if not self.load_data(): return False @@ -1120,8 +1415,11 @@ class SeatAllocationSystem: self.logger.log("开始座位分配") self.logger.log("=" * 60) + # 选择分组方式 + grouping_method = self.choose_grouping_method() + # 分析人员连坐需求 - if not self.analyze_seating_requirements(): + if not self.analyze_seating_requirements(use_phone_grouping=(grouping_method == 'phone')): return False # 高级座位结构分析 @@ -1139,6 +1437,29 @@ class SeatAllocationSystem: self.logger.log("\n❌ 座位分配失败!") return False + def choose_grouping_method(self): + """选择分组方式""" + self.logger.log("\n=== 选择连坐分组方式 ===") + self.logger.log("1. 备注分组 - 根据备注数字识别连坐组(默认)") + self.logger.log("2. 手机号分组 - 根据相同手机号识别连坐组") + + while True: + try: + choice = input("\n请选择分组方式 (1/2,直接回车选择默认): ").strip() + + if choice == '' or choice == '1': + self.logger.log("✅ 选择备注分组模式") + return 'remark' + elif choice == '2': + self.logger.log("✅ 选择手机号分组模式") + return 'phone' + else: + print("请输入 1 或 2") + + except KeyboardInterrupt: + self.logger.log("\n用户取消操作") + return 'remark' + def main(): """主函数""" print("=" * 60) diff --git a/simple_build.py b/simple_build.py deleted file mode 100644 index 91497e1..0000000 --- a/simple_build.py +++ /dev/null @@ -1,232 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -简化构建脚本 -在当前平台构建可执行文件 -""" - -import os -import sys -import subprocess -import platform -import shutil -from pathlib import Path - -def get_platform_info(): - """获取平台信息""" - system = platform.system() - machine = platform.machine().lower() - - if system == 'Windows': - if machine in ['amd64', 'x86_64']: - return 'windows_x64' - elif machine in ['i386', 'i686', 'x86']: - return 'windows_x86' - else: - return f'windows_{machine}' - elif system == 'Darwin': - if machine in ['arm64', 'aarch64']: - return 'macos_arm64' - else: - return 'macos_x64' - elif system == 'Linux': - return f'linux_{machine}' - else: - return f'{system.lower()}_{machine}' - -def install_dependencies(): - """安装依赖""" - print("安装依赖包...") - packages = ['pandas', 'openpyxl', 'pyinstaller'] - - for package in packages: - try: - __import__(package) - print(f"✅ {package} 已安装") - except ImportError: - print(f"📦 安装 {package}...") - try: - subprocess.check_call([sys.executable, '-m', 'pip', 'install', package]) - print(f"✅ {package} 安装成功") - except subprocess.CalledProcessError: - print(f"❌ {package} 安装失败") - return False - return True - -def build_executable(): - """构建可执行文件""" - print("\n开始构建可执行文件...") - - # 获取平台信息 - platform_name = get_platform_info() - exe_name = f"座位分配系统_{platform_name}" - - print(f"目标平台: {platform_name}") - print(f"输出文件: {exe_name}") - - # 清理之前的构建 - if os.path.exists('dist'): - shutil.rmtree('dist') - if os.path.exists('build'): - shutil.rmtree('build') - - # 构建命令 - cmd = [ - sys.executable, '-m', 'PyInstaller', - '--onefile', - '--console', - '--clean', - '--name', exe_name, - 'seat_allocation_system.py' - ] - - try: - print(f"执行命令: {' '.join(cmd)}") - result = subprocess.run(cmd, capture_output=True, text=True) - - if result.returncode == 0: - print("✅ 构建成功!") - - # 检查生成的文件 - if platform.system() == 'Windows': - exe_path = Path('dist') / f'{exe_name}.exe' - else: - exe_path = Path('dist') / exe_name - - 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("❌ 未找到生成的文件") - return False, None - else: - print("❌ 构建失败!") - print("错误输出:") - print(result.stderr) - return False, None - - except Exception as e: - print(f"❌ 构建过程中出现错误: {e}") - return False, None - -def create_distribution(): - """创建分发包""" - print("\n创建分发包...") - - platform_name = get_platform_info() - package_name = f"座位分配系统_{platform_name}_分发包" - package_dir = Path(package_name) - - # 创建分发目录 - if package_dir.exists(): - shutil.rmtree(package_dir) - package_dir.mkdir() - - # 复制可执行文件 - dist_dir = Path('dist') - if dist_dir.exists(): - for file in dist_dir.iterdir(): - if file.is_file(): - shutil.copy2(file, package_dir) - print(f"复制文件: {file.name}") - - # 复制示例文件 - if Path('人员信息.xlsx').exists(): - shutil.copy2('人员信息.xlsx', package_dir / '人员信息_示例.xlsx') - print("复制示例文件: 人员信息_示例.xlsx") - - if Path('座位信息.xlsx').exists(): - shutil.copy2('座位信息.xlsx', package_dir / '座位信息_示例.xlsx') - print("复制示例文件: 座位信息_示例.xlsx") - - # 创建使用说明 - readme_content = f"""座位分配系统 使用说明 - -平台: {platform_name} -构建时间: {platform.platform()} - -使用方法: -1. 准备Excel文件 - - 人员信息.xlsx: 包含姓名、证件信息、备注等 - - 座位信息.xlsx: 包含区域、楼层、排号、座位号等 - -2. 运行程序 - - 将可执行文件放在Excel文件同一目录 - - 双击运行可执行文件 - - 等待处理完成 - -3. 查看结果 - - 座位信息_最终分配.xlsx: 分配结果 - - 最终座位分配日志.xlsx: 详细记录 - - seat_allocation_log.txt: 运行日志 - -功能特点: -- 支持1-10人连坐需求 -- 自动处理不连续座位 -- 完整的数据校验 -- 详细的分配日志 - -注意事项: -- 确保Excel文件格式正确 -- 备注数字表示连坐人数 -- 运行时会在同目录生成结果文件 -""" - - with open(package_dir / '使用说明.txt', 'w', encoding='utf-8') as f: - f.write(readme_content) - - print(f"✅ 分发包已创建: {package_dir}") - return package_dir - -def main(): - """主函数""" - print("座位分配系统 - 简化构建工具") - print("=" * 50) - - # 显示系统信息 - print(f"系统: {platform.system()} {platform.release()}") - print(f"架构: {platform.machine()}") - print(f"Python: {sys.version}") - - # 检查主程序文件 - if not os.path.exists('seat_allocation_system.py'): - print("❌ 未找到 seat_allocation_system.py 文件") - return - - # 安装依赖 - if not install_dependencies(): - print("❌ 依赖安装失败") - return - - # 构建可执行文件 - success, exe_path = build_executable() - if not success: - print("❌ 构建失败") - return - - # 创建分发包 - package_dir = create_distribution() - - print("\n🎉 构建完成!") - print(f"✅ 可执行文件: {exe_path}") - print(f"✅ 分发包: {package_dir}") - - # 平台特定说明 - if platform.system() == 'Windows': - print("\n📝 Windows使用说明:") - print("- 可以直接在Windows系统上运行") - print("- 确保安装了Visual C++ Redistributable") - elif platform.system() == 'Darwin': - print("\n📝 macOS使用说明:") - print("- 只能在macOS系统上运行") - print("- 如需Windows版本,请在Windows系统上构建") - print("- 或使用GitHub Actions自动构建") - else: - print(f"\n📝 {platform.system()}使用说明:") - print("- 只能在相同系统上运行") - print("- 如需其他平台版本,请在对应系统上构建") - -if __name__ == "__main__": - main() diff --git a/运行座位分配系统.bat b/运行座位分配系统.bat deleted file mode 100644 index aafa296..0000000 --- a/运行座位分配系统.bat +++ /dev/null @@ -1,116 +0,0 @@ -@echo off -chcp 65001 >nul -title 座位分配系统 v2.0 - -:: 设置颜色 -color 0F - -echo. -echo ========================================== -echo 座位分配系统 v2.0 -echo ========================================== -echo. -echo 正在检查运行环境... -echo. - -:: 检查可执行文件是否存在 -if not exist "座位分配系统.exe" ( - echo [错误] 未找到 座位分配系统.exe 文件 - echo. - echo 请确保以下文件在同一目录下: - echo - 座位分配系统.exe - echo - 人员信息.xlsx - echo - 座位信息.xlsx - echo. - pause - exit /b 1 -) - -echo [成功] 程序文件检查通过 - -:: 检查Excel文件 -echo 正在扫描Excel文件... - -:: 计算xlsx文件数量 -set count=0 -for %%f in (*.xlsx) do ( - :: 排除输出和示例文件 - echo "%%f" | findstr /v /i "最终分配\|分配日志\|示例\|temp\|backup" >nul - if not errorlevel 1 ( - set /a count+=1 - echo 发现文件: %%f - ) -) - -if %count% equ 0 ( - echo. - echo [错误] 未找到Excel数据文件 - echo. - echo 请确保当前目录下有Excel数据文件: - echo 1. 人员信息文件 (5-6列): 姓名、证件类型、证件号、手机号、备注等 - echo 2. 座位信息文件 (10+列): 区域、楼层、排号、座位号等 - echo. - echo 提示: 程序会自动识别文件类型,无需固定文件名 - pause - exit /b 1 -) - -if %count% gtr 2 ( - echo. - echo [警告] 发现超过2个Excel文件 - echo 为避免识别混淆,请确保目录下只有2个数据文件 - echo 程序会自动排除输出文件和示例文件 - echo. - echo 当前Excel文件: - for %%f in (*.xlsx) do echo %%f - echo. - echo 请移除多余文件后重试 - pause - exit /b 1 -) - -echo [成功] 找到 %count% 个Excel文件,程序将自动识别文件类型 - -echo. -echo ========================================== -echo 开始运行程序 -echo ========================================== -echo. -echo 所有检查通过,正在启动座位分配系统... -echo 请等待程序运行完成... -echo. - -:: 运行程序并捕获错误 -"座位分配系统.exe" -set "exit_code=%ERRORLEVEL%" - -echo. -echo ========================================== -echo 运行结果 -echo ========================================== -echo. - -if %exit_code% equ 0 ( - echo [成功] 程序运行成功! - echo. - echo 输出文件说明: - echo - 座位信息_最终分配.xlsx: 最终座位分配结果 - echo - 最终座位分配日志.xlsx: 详细分配记录 - echo - seat_allocation_log.txt: 运行日志文件 - echo. - echo 您可以用Excel打开xlsx文件查看结果 -) else ( - echo [错误] 程序运行出现错误 (错误代码: %exit_code%) - echo. - echo 可能的原因: - echo 1. 数据文件格式不正确 - echo 2. 文件权限不足 - echo 3. 磁盘空间不足 - echo 4. 缺少必要的依赖 - echo. - echo 请查看 seat_allocation_log.txt 获取详细错误信息 -) - -echo. -echo 按任意键退出... -pause >nul \ No newline at end of file