吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1344|回复: 22
收起左侧

[求助] 写了个自己门店用的排号小程序但是不会打包,求指教

[复制链接]
sevendad 发表于 2025-4-24 19:26
import tkinter as tk
from tkinter import messagebox, ttk
from datetime import datetime, date
import re
import json
import os

DATA_FILE = "daily_queue.json"  # 数据文件路径

class QueueSystem(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("☯️魏氏奇门轩智能排号系统☯")
        self.geometry("500x400")
        self.resizable(False, False)
        
        # 初始化数据
        self.queue = []
        self.current_number = 0
        
        # 界面初始化流程优化:数据加载 -> 界面创建 -> 样式配置 -> 状态检查
        self._load_daily_data()
        self.init_ui()
        self.style_config()
        self.center_window()
        self.update_time()
        self._check_button_state()

    def init_ui(self):
        """创建界面组件"""
        # 时间显示
        self.time_label = tk.Label(self, font=('微软雅黑', 12, 'italic'), fg='#666')
        self.time_label.pack(pady=5)

        # 输入区域
        input_frame = ttk.Frame(self, padding=(10, 5))
        input_frame.pack(fill=tk.X, padx=10)

        # 手机号输入(带验证)
        ttk.Label(input_frame, text="问策者手机号:").grid(row=0, column=0, sticky=tk.W, padx=5)
        self.phone_var = tk.StringVar()
        self.phone_entry = ttk.Entry(
            input_frame,
            textvariable=self.phone_var,
            width=20,
            valIDAte='key',
            validatecommand=(self.register(self.validate_phone), '%P')
        )
        self.phone_entry.grid(row=0, column=1, pady=5, padx=5, sticky=tk.W)

        # 人数选择(严格数字验证)
        ttk.Label(input_frame, text="排号测算人数:").grid(row=0, column=2, sticky=tk.W, padx=5)
        self.people_var = tk.IntVar(value=1)
        self.people_spinbox = ttk.Spinbox(
            input_frame,
            from_=1,
            to=9,
            textvariable=self.people_var,
            width=5,
            wrap=True,
            validate='key',
            validatecommand=(self.register(self.validate_people), '%P')
        )
        self.people_spinbox.grid(row=0, column=3, pady=5, padx=5, sticky=tk.W)

        # 按钮组
        button_frame = ttk.Frame(input_frame, padding=(5, 0))
        button_frame.grid(row=1, columnspan=4, pady=10, sticky=tk.W)

        # 排号按钮
        self.submit_btn = ttk.Button(
            button_frame,
            text="立即排号",
            style='TButton',
            command=self.submit_queue,
            padding=(12, 6)
        )
        self.submit_btn.pack(side=tk.LEFT, padx=8)

        # 刷新按钮(带动画)
        self.refresh_btn = ttk.Button(
            button_frame,
            text="🔄 刷新",
            style='Refresh.TButton',
            command=self.refresh_queue,
            padding=(8, 6),
            width=8
        )
        self.refresh_btn.pack(side=tk.LEFT, padx=8)

        # 叫号按钮
        self.call_button = ttk.Button(
            button_frame,
            text="▶ 立即叫号",
            style='Success.TButton',
            command=self.call_next,
            padding=(12, 6),
            state='disabled'
        )
        self.call_button.pack(side=tk.LEFT, padx=8)

        # 队列显示
        queue_frame = ttk.Frame(
            self,
            padding=10,
            relief='solid',
            borderwidth=1,
            style='Border.TFrame'
        )
        queue_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        self.queue_list = tk.Listbox(
            queue_frame,
            width=60,
            height=10,
            font=('微软雅黑', 10),
            activestyle='none',
            selectbackground='#E0E0E0'
        )
        self.queue_list.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        ttk.Scrollbar(queue_frame, orient='vertical', command=self.queue_list.yview).pack(side=tk.RIGHT, fill=tk.Y)

    def style_config(self):
        """统一配置界面样式"""
        style = ttk.Style()
        
        # 基础按钮样式
        style.configure('TButton',
            foreground='#0078D4',
            font=('微软雅黑', 10, 'bold'),
            padding=6,
            relief='flat'
        )
        
        # 成功按钮样式(叫号按钮)
        style.configure('Success.TButton',
            foreground='#22C55E',
            font=('微软雅黑', 11, 'bold'),
            padding=(12, 6),
            relief='raised',
            borderwidth=2,
            background='#EBF5EC'
        )
        style.map('Success.TButton',
            relief=[('pressed', 'sunken'), ('active', 'raised')],
            background=[('active', '#E8F5E9')]
        )
        
        # 刷新按钮样式
        style.configure('Refresh.TButton',
            foreground='#666',
            font=('微软雅黑', 10, 'bold'),
            padding=6,
        )
        
        # 边框框架样式
        style.configure('Border.TFrame',
            borderwidth=1,
            relief='solid',
            lightcolor='#E0E0E0',
            darkcolor='#E0E0E0'
        )
        style.layout('Border.TFrame', [
            ('Border.TFrame.border', {
                'sticky': 'nswe',
                'border': 1,
                'children': [('Border.TFrame.padding', {'sticky': 'nswe'})]
            })
        ])

    def _load_daily_data(self):
        """加载当天数据,跨天自动重置"""
        today = date.today().isoformat()
        try:
            with open(DATA_FILE, 'r') as f:
                data = json.load(f)
                if data.get('date') == today:
                    self.queue = data['queue']
                    self.current_number = data.get('current_number', 0)
                else:
                    self._reset_daily_data()  # 跨天重置
        except (FileNotFoundError, json.JSONDecodeError):
            self._reset_daily_data()  # 初始化或文件损坏时重置

    def _reset_daily_data(self):
        """重置当天数据(跨天/初始化/文件错误时调用)"""
        self.queue = []
        self.current_number = 0
        self._save_daily_data()

    def _save_daily_data(self):
        """保存当前数据到文件"""
        try:
            today = date.today().isoformat()
            data = {
                'date': today,
                'queue': self.queue,
                'current_number': self.current_number
            }
            with open(DATA_FILE, 'w') as f:
                json.dump(data, f, indent=2)
        except Exception as e:
            messagebox.showerror("数据保存错误", f"保存数据时发生错误:{str(e)}", parent=self)

    def validate_phone(self, new_value):
        """手机号验证:11位数字,允许空值(输入过程中)"""
        return len(new_value) <= 11 and new_value.isdigit() or new_value == ''

    def validate_people(self, new_value):
        """人数验证:1-9的数字,允许删除后自动回退"""
        return not new_value or (new_value.isdigit() and 1 <= int(new_value) <= 9)

    def submit_queue(self):
        """处理排号逻辑"""
        phone = self.phone_var.get().strip()
        people = self.people_var.get()

        if not self._validate_phone_format(phone):
            return
        if not self._validate_people_count(people):
            return

        existing_people = sum(q['people'] for q in self.queue if q['status'] == '等待中')
        remaining = people
        
        while remaining > 0:
            group = min(remaining, 2)  # 每组最多2人(业务规则)
            self.current_number += 1
            self.queue.append({
                'number': f'V{self.current_number:03d}',
                'phone': phone,
                'people': group,
                'total': existing_people,
                'status': '等待中',
                'time': datetime.now().strftime('%H:%M')
            })
            existing_people += group
            remaining -= group
            
            # 非最后一组且人数>0时询问是否继续
            if remaining > 0 and not self._ask_continue(phone, remaining):
                break

        self._save_daily_data()
        self._update_queue_display()
        self._adjust_window_size()
        self.clear_input_fields()
        self._check_button_state()

    def _validate_phone_format(self, phone):
        """验证手机号格式并显示错误"""
        if not re.fullmatch(r'^\d{11}$', phone):
            messagebox.showerror("号码错误", f"&#10060; 请输入11位有效手机号(当前:{phone})", parent=self)
            return False
        return True

    def _validate_people_count(self, people):
        """验证人数并显示错误"""
        if not (1 <= people <= 9):
            messagebox.showerror("人数错误", f"&#128101; 请选择1-9人(当前:{people}人)", parent=self)
            return False
        return True

    def call_next(self):
        """处理叫号逻辑"""
        waiting_queue = [q for q in self.queue if q['status'] == '等待中']
        if not waiting_queue:
            messagebox.showwarning("队列已空", "&#128227; 目前没有等待的号码", parent=self)
            return

        current_group = waiting_queue[0]
        current_group['status'] = '已叫号'
        current_group['call_time'] = datetime.now().strftime('%H:%M')
        
        # 更新后续队列的等待人数
        current_total = 0
        for item in self.queue:
            if item['status'] == '等待中':
                item['total'] = current_total
                current_total += item['people']

        self._save_daily_data()
        self._show_call_notification(current_group)
        self._update_queue_display()
        self._adjust_window_size()
        self._check_button_state()

    def _update_queue_display(self):
        """更新队列显示"""
        self.queue_list.delete(0, tk.END)
        for idx, item in enumerate(self.queue, 1):
            bg_color = '#F8F9FA' if idx % 2 else '#FFFFFF'
            if item['status'] == '已叫号':
                bg_color = '#E9ECEF'
            
            status_prefix = '&#9989;' if item['status'] == '已叫号' else '&#8987;'
            time_display = item.get('call_time', item['time'])
            
            queue_text = (
                f"{status_prefix} {item['number']}  {item['phone']} "
                f"&#128101;{item['people']}人  前面:{item['total']}人  "
                f"&#9200; {time_display}"
            )
            self.queue_list.insert(tk.END, queue_text)
            self.queue_list.itemconfig(idx-1, bg=bg_color)

    def _adjust_window_size(self):
        """根据队列长度自动调整窗口高度"""
        item_height = 28
        required_height = 400 + (len(self.queue) - 10) * item_height
        self.geometry(f"500x{max(400, required_height)}+{self.winfo_x()}+{self.winfo_y()}")

    def update_time(self):
        """实时更新时间显示,跨天自动重置数据"""
        now = datetime.now()
        self.time_label.config(text=f"&#128197; {now.strftime('%Y-%m-%d')}  {now.strftime('%H:%M:%S')}")
        
        # 跨天自动重置(每天0点后首次检测到日期变化时重置)
        if date.today() != date.fromisoformat(self._get_last_save_date()):
            self._reset_daily_data()
            messagebox.showinfo("每日重置", "&#127749; 新的一天开始,今日数据已重置", parent=self)
        
        self.after(1000, self.update_time)

    def _get_last_save_date(self):
        """获取最后保存的日期(避免文件不存在时错误)"""
        try:
            with open(DATA_FILE, 'r') as f:
                return json.load(f).get('date', None)
        except:
            return None

    def refresh_queue(self):
        """刷新队列数据(带动画效果)"""
        self._load_daily_data()
        self._update_queue_display()
        self._adjust_window_size()
        self._check_button_state()
        
        # 动画效果:交替显示刷新图标
        self.refresh_btn.config(text="&#10227;")
        self.after(100, lambda: self.refresh_btn.config(text="&#128260;"))
        self.after(200, lambda: self.refresh_btn.config(text="&#10227;"))
        self.after(300, lambda: self.refresh_btn.config(text="&#128260;"))

    def _check_button_state(self):
        """更新按钮可用状态"""
        has_waiting = any(item['status'] == '等待中' for item in self.queue)
        self.call_button.config(state='normal' if has_waiting else 'disabled')

    def clear_input_fields(self):
        """清空输入框并聚焦"""
        self.phone_var.set('')
        self.people_var.set(1)
        self.phone_entry.focus_set()

    def _ask_continue(self, phone, remaining):
        """询问是否继续使用当前手机号排号"""
        return messagebox.askyesno(
            "继续排号",
            f"&#8505;&#65039; 剩余{remaining}人需要排号\n是否继续使用当前手机号?\n&#128241; {phone[-4:]}*******",
            icon='question',
            parent=self
        )

    def _show_call_notification(self, item):
        """显示叫号通知"""
        messagebox.showinfo(
            "号码已叫",
            f"&#128227; 请 {item['number']} 到前台\n"
            f"&#9200; 取号时间:{item['time']}\n"
            f"&#128222; 手机号:{item['phone']}",
            parent=self,
            icon='info'
        )

    def center_window(self):
        """窗口居中显示"""
        self.update_idletasks()
        screen_width = self.winfo_screenwidth()
        screen_height = self.winfo_screenheight()
        x = (screen_width - 500) // 2
        y = (screen_height - self.winfo_height()) // 2
        self.geometry(f"500x{self.winfo_height()}+{x}+{y}")

if __name__ == "__main__":
    app = QueueSystem()
    app.mainloop()
这是代码,我想将它打包成可执行的exe文件,小白不懂,尝试多次,不成功,请大神指点一下

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

feiyuya 发表于 2025-4-24 21:09
代码有问题吧,打包不了啊
SVIP9大会员 发表于 2025-4-24 21:20
你这里出错了
        # 手机号输入(带验证)
        ttk.Label(input_frame, text="问策者手机号:").grid(row=0, column=0, sticky=tk.W, padx=5)
        self.phone_var = tk.StringVar()
        self.phone_entry = ttk.Entry(
            input_frame,
            textvariable=self.phone_var,
            width=20,
            valIDAte='key',
            validatecommand=(self.register(self.validate_phone), '%P')
        )


改成这样
validate='key',

大小写出错了,然后在打包!
ashortname 发表于 2025-4-24 21:24
bydlyzx 发表于 2025-4-24 21:44
你在任何一个 ai 编程工具(trae/cursor/VSCode)中说:
请帮我打包成win平台可独立执行的exe文件,
然后就打包啦。

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
sevendad + 1 + 1 我很赞同!

查看全部评分

博爵 发表于 2025-4-24 22:21
运行不了,打包我使用的Auto Py to Exe,一个cmd命令就可以打开
 楼主| sevendad 发表于 2025-4-24 23:06
feiyuya 发表于 2025-4-24 21:09
代码有问题吧,打包不了啊

我也是新手,靠AI一点一点弄的
 楼主| sevendad 发表于 2025-4-24 23:07
SVIP9大会员 发表于 2025-4-24 21:20
你这里出错了
        # 手机号输入(带验证)
        ttk.Label(input_frame, text="问策者手机号:").g ...

谢谢大神指教,请问该如何打包啊,我用的py,打包多次不成功,一直报错,380动态链接库啥的
 楼主| sevendad 发表于 2025-4-24 23:08
博爵 发表于 2025-4-24 22:21
运行不了,打包我使用的Auto Py to Exe,一个cmd命令就可以打开

谢谢啦,我去试试
 楼主| sevendad 发表于 2025-4-24 23:08
bydlyzx 发表于 2025-4-24 21:44
你在任何一个 ai 编程工具(trae/cursor/VSCode)中说:
请帮我打包成win平台可独立执行的exe文件,
然后 ...

好的非常感谢,我去试试
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-5-14 22:57

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表