吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1648|回复: 42
上一主题 下一主题
收起左侧

[Python 转载] 用AI写的会议室预约程序网页版

[复制链接]
跳转到指定楼层
楼主
尖叫的体毛 发表于 2025-4-14 16:32 回帖奖励
本帖最后由 尖叫的体毛 于 2025-4-14 16:37 编辑

因个人公司需要,故有此项目,所有代码均为AI生成
涉及部分格式、语法、个人使用习惯问题等均可略过,关注关键代码及成品即可


首先展示下成品:
1.首页

2.管理员登录后审批、会议室管理

3.审批通过后首页右上角的预约日历会显示具体信息

4.申请人邮箱会收到确认邮件


关键代码:
[Python] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
from flask import Flask, render_template, request, redirect, url_for, session, flash, abortfrom flask_mail import Mail, Message
from extensions import db
from models import Room, Booking
from config import Config
from datetime import datetime, timedelta
import re
import uuid
 
app = Flask(__name__)
app.config.from_object(Config)
 
# 初始化扩展
db.init_app(app)
mail = Mail(app)
 
 
@app.context_processor
def inject_global_vars():
    def generate_time_slots():
        return [f"{h:02d}:{m}" for h in range(8, 21) for m in ('00', '30')]
 
    min_date = (datetime.now() + timedelta(hours=1)).strftime('%Y-%m-%d')
    return dict(time_slots=generate_time_slots(), min_date=min_date)
 
# 错误处理
@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404
 
# 用户路由
@app.route('/')
def index():
    rooms = Room.query.filter_by(is_active=True).all()
    # 计算最小可用日期(当前日期+1小时)
    min_date = (datetime.now() + timedelta(hours=1)).strftime('%Y-%m-%d')
    return render_template('index.html', rooms=rooms, min_date=min_date)
 
 
@app.route('/book', methods=['POST'])
def book_room():
    try:
        # 获取表单数据
        booking_date = request.form['booking_date']
        start_time_str = f"{booking_date} {request.form['start_time']}"
        end_time_str = f"{booking_date} {request.form['end_time']}"
        applicant_name = request.form.get('applicant_name', '').strip()
        company = request.form.get('company', '').strip()
        phone = request.form.get('phone', '').strip()
        purpose = request.form.get('purpose', '').strip()
 
        # 转换为datetime对象
        start_time = datetime.strptime(start_time_str, '%Y-%m-%d %H:%M')
        end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M')
 
        if len(applicant_name) < 2 or len(applicant_name) > 50:
            flash("姓名需为2-50个字符", "danger")
            return redirect(url_for('index'))
 
        if len(company) < 2 or len(company) > 100:
            flash("公司名称需为2-100个字符", "danger")
            return redirect(url_for('index'))
 
        if not re.match(r'^1[3-9]\d{9}$', phone):
            flash("请输入有效的中国大陆手机号码", "danger")
            return redirect(url_for('index'))
 
        # 验证时间有效性
        now = datetime.now()
        if start_time < now + timedelta(hours=1):
            flash("请至少提前1小时预约", "danger")
            return redirect(url_for('index'))
 
        if end_time <= start_time:
            flash("结束时间必须晚于开始时间", "danger")
            return redirect(url_for('index'))
 
 
 
        # 检查时间冲突
        conflicting_booking = Booking.query.filter(
            Booking.room_id == request.form['room_id'],
            Booking.start_time < end_time,
            Booking.end_time > start_time,
            Booking.status == '已批准'
        ).first()
 
        if conflicting_booking:
            flash("该时间段已被预约", "danger")
            return redirect(url_for('index'))
 
        # 创建预约
        booking = Booking(
            email=request.form['email'],
            room_id=request.form['room_id'],
            start_time=start_time,
            end_time=end_time,
            cancel_code=str(uuid.uuid4()),
            applicant_name = applicant_name,
            company = company,
            phone = phone,
            purpose = purpose
        )
 
        # 新增保存前的验证
        if not booking.validate_phone():
            flash("手机号码格式错误", "danger")
            return redirect(url_for('index'))
 
        db.session.add(booking)
        db.session.commit()
        send_confirmation_email(booking)
        flash("预约申请已提交,请查收邮件确认", "success")
        return redirect(url_for('index', booking_success='true'))
 
    except Exception as e:
        db.session.rollback()
        app.logger.error(f"预约错误: {str(e)}")
        flash("预约失败,请检查输入信息", "danger")
 
    return redirect(url_for('index'))
 
 
def send_confirmation_email(booking):
    try:
        msg = Message("会议室预约确认",
                      sender=app.config['MAIL_USERNAME'],
                      recipients=[booking.email])
        msg.body = render_template(
            'emails/confirmation.txt',
            booking=booking,
            applicant_name=booking.applicant_name,  # 新增
            company=booking.company,  # 新增
            phone=booking.phone,  # 新增
            purpose=booking.purpose,  # 新增
            cancel_url=url_for('cancel_booking', code=booking.cancel_code, _external=True)
        )
        mail.send(msg)
    except Exception as e:
        app.logger.error(f"邮件发送失败: {str(e)}")
 
def send_approval_email(booking):
    """发送审批通过确认邮件"""
    try:
        msg = Message(
            "会议室预约已通过",
            sender=app.config['MAIL_USERNAME'],
            recipients=[booking.email]
        )
        msg.html = render_template(
            'emails/approval.html',
            booking=booking,
            contact_email=app.config['MAIL_USERNAME']
        )
        mail.send(msg)
        app.logger.info(f"已发送审批通过邮件至 {booking.email}")
    except Exception as e:
        app.logger.error(f"审批通过邮件发送失败: {str(e)}")
 
 
@app.route('/admin/bookings/approve/<int:id>')
def approve_booking_reason(id):
    if not session.get('admin_logged_in'):
        abort(403)
 
    try:
        booking = Booking.query.get_or_404(id)
        booking.status = '已批准'
        db.session.commit()
 
        # 发送审批通过邮件
        send_approval_email(booking)
 
        flash("预约已批准并发送确认邮件", "success")
    except Exception as e:
        db.session.rollback()
        app.logger.error(f"审批操作失败: {str(e)}")
        flash("操作失败,请检查日志", "danger")
 
    return redirect(url_for('manage_bookings'))
 
def send_rejection_email(booking, reason=None):
    """发送拒绝通知邮件"""
    try:
        msg = Message("会议室预约未通过审批",
                      sender=app.config['MAIL_USERNAME'],
                      recipients=[booking.email])
 
        # 使用HTML模板
        msg.html = render_template(
            'emails/rejection.html',
            booking=booking,
            reason=reason,
            contact_email=app.config['MAIL_USERNAME']
        )
 
        mail.send(msg)
        app.logger.info(f"已发送拒绝通知至 {booking.email}")
    except Exception as e:
        app.logger.error(f"拒绝邮件发送失败: {str(e)}")
 
 
@app.route('/admin/bookings/reject/<int:id>', methods=['GET', 'POST'])
def reject_booking_with_reason(id):
    if not session.get('admin_logged_in'):
        abort(403)
 
    booking = Booking.query.get_or_404(id)
 
    if request.method == 'POST':
        # 获取拒绝原因
        rejection_reason = request.form.get('reason', '不符合会议室使用规定')
 
        booking.status = '已拒绝'
        db.session.commit()
 
        # 发送拒绝邮件
        send_rejection_email(booking, rejection_reason)
 
        flash("已拒绝该预约并通知申请人", "success")
        return redirect(url_for('manage_bookings'))
 
    # GET请求显示原因填写表单
    return render_template('admin/reject_reason.html', booking=booking)
 
@app.route('/cancel/<string:code>')
def cancel_booking(code):
    booking = Booking.query.filter_by(cancel_code=code).first()
    if booking:
        room_name = booking.room.name
        time_str = booking.start_time.strftime('%Y-%m-%d %H:%M')
        db.session.delete(booking)
        db.session.commit()
 
        # 发送取消确认邮件
        try:
            msg = Message("预约取消确认",
                          sender=app.config['MAIL_USERNAME'],
                          recipients=[booking.email])
            msg.body = f"""您的预约已取消:
 
                会议室:{room_name}
                原定时间:{time_str}
 
                如需重新预约,请访问:{url_for('index', _external=True)}"""
            mail.send(msg)
        except Exception as e:
            app.logger.error(f"取消确认邮件发送失败: {str(e)}")
 
        return render_template('bookings/cancel.html', booking=booking)
 
    return render_template('bookings/cancel.html', booking=None), 404
 
# 管理员路由
@app.route('/admin')
def admin_dashboard():
    if not session.get('admin_logged_in'):
        return redirect(url_for('admin_login'))
    room_count = Room.query.count()
    pending_booking_count = Booking.query.filter_by(status='待审批').count()
    return render_template('admin/dashboard.html',
        room_count = room_count,
    pending_booking_count = pending_booking_count)
 
 
@app.route('/admin/login', methods=['GET', 'POST'])
def admin_login():
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        if username == app.config['ADMIN_USERNAME'] and password == app.config['ADMIN_PASSWORD']:
            session['admin_logged_in'] = True
            return redirect(url_for('admin_dashboard'))
        flash("用户名或密码错误", "danger")
    return render_template('auth/login.html')
 
 
@app.route('/admin/logout')
def admin_logout():
    session.pop('admin_logged_in', None)
    return redirect(url_for('index'))
 
 
@app.route('/admin/rooms')
def manage_rooms():
    if not session.get('admin_logged_in'):
        return redirect(url_for('admin_login'))
    rooms = Room.query.all()
    return render_template('admin/rooms.html', rooms=rooms)
 
 
@app.route('/admin/room/add', methods=['POST'])
def add_room():
    if not session.get('admin_logged_in'):
        abort(403)
    try:
        room = Room(
            name=request.form['name'],
            capacity=int(request.form['capacity']),
            equipment=request.form.get('equipment', '')
        )
        db.session.add(room)
        db.session.commit()
        flash("会议室添加成功", "success")
    except Exception as e:
        db.session.rollback()
        app.logger.error(f"添加会议室失败: {str(e)}")
        flash("添加会议室失败", "danger")
    return redirect(url_for('manage_rooms'))
 
 
@app.route('/admin/room/delete/<int:id>')
def delete_room(id):
    if not session.get('admin_logged_in'):
        abort(403)
    room = Room.query.get_or_404(id)
    try:
        db.session.delete(room)
        db.session.commit()
        flash("会议室删除成功", "success")
    except Exception as e:
        db.session.rollback()
        app.logger.error(f"删除失败: {str(e)}")
        flash("删除失败,请先处理相关预约", "danger")
    return redirect(url_for('manage_rooms'))
 
 
@app.route('/admin/bookings')
def manage_bookings():
    if not session.get('admin_logged_in'):
        return redirect(url_for('admin_login'))
    # 添加排序和新字段查询
    bookings = Booking.query.order_by(Booking.start_time.desc()).all()
    return render_template('admin/bookings.html',
                         bookings=bookings,
                         datetime=datetime)  # 传递datetime到模板
    bookings = Booking.query.order_by(Booking.created_at.desc()).all()
    return render_template('admin/bookings.html', bookings=bookings)
 
 
 
@app.route('/admin/bookings/approve/<int:id>')
def approve_booking(id):
    if not session.get('admin_logged_in'):
        abort(403)
    booking = Booking.query.get_or_404(id)
    booking.status = '已批准'
    db.session.commit()
    return redirect(url_for('manage_bookings'))
 
 
@app.route('/admin/bookings/reject/<int:id>')
def reject_booking(id):
    if not session.get('admin_logged_in'):
        abort(403)
    booking = Booking.query.get_or_404(id)
    booking.status = '已拒绝'
    db.session.commit()
    return redirect(url_for('manage_bookings'))
 
 
# 添加在现有路由附近
@app.route('/calendar')
def booking_calendar():
    # 修正:从datetime模块获取当前时间
    current_time = datetime.now()
    # 获取所有已批准的预约
    approved_bookings = Booking.query.filter(
        Booking.status == '已批准',
        Booking.end_time > current_time
    ).order_by(Booking.start_time.asc()).all()
    # 按日期和会议室分组
    bookings_dict = {}
    for booking in approved_bookings:
        date_str = booking.start_time.strftime('%Y-%m-%d')
        if date_str not in bookings_dict:
            bookings_dict[date_str] = {}
        if booking.room.name not in bookings_dict[date_str]:
            bookings_dict[date_str][booking.room.name] = []
        bookings_dict[date_str][booking.room.name].append({
            'start': booking.start_time.strftime('%H:%M'),
            'end': booking.end_time.strftime('%H:%M'),
            'applicant': booking.applicant_name
        })
 
    return render_template('calendar.html',
                           bookings=bookings_dict,
                           dates=sorted(bookings_dict.keys()),
                           datetime=datetime)
 
if __name__ == '__main__':
    with app.app_context():
        db.create_all()
    app.run(host='0.0.0.0', port=5000, debug=True)


使用前请先配置目录下的config文件:
[Python] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
import os
from dotenv import load_dotenv
 
load_dotenv()
 
class Config:
    SECRET_KEY = os.getenv('SECRET_KEY', 'dev-secret-key')
    SQLALCHEMY_DATABASE_URI = 'sqlite:///meetings.db'
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    MAIL_SERVER = os.getenv('MAIL_SERVER', 'smtp.qq.com')
    MAIL_PORT = int(os.getenv('MAIL_PORT', 465))
    MAIL_USE_SSL = True  # 必须启用SSL
    MAIL_USE_TLS = False  # 禁用TLS
    MAIL_USERNAME = os.getenv('MAIL_USERNAME', 'XXXXXX@qq.com'# &#9989;我使用的是自己的邮箱
    MAIL_PASSWORD = os.getenv('MAIL_PASSWORD', 'XXXXXX'# &#9989;这个就是邮箱的授权码,用来发邮件的
    ADMIN_USERNAME = 'admin'#管理员帐号
    ADMIN_PASSWORD = 'admin123'#管理员密码
    # 新增管理员邮箱配置
    ADMIN_EMAIL = 'XXXX@XXXX.com'  # 管理员联系邮箱,会显示的邮箱结尾,纯文字




最后,设置完py打开运行目录下的app.py,浏览器打开本机IP:5000访问

下载:https://wwre.lanzouq.com/i7qgI2tkr82j 密码:52pj
如有违规,管理请删,谢谢

预约成功.png (69.9 KB, 下载次数: 2)

预约成功.png

免费评分

参与人数 4吾爱币 +10 热心值 +3 收起 理由
Learner + 1 + 1 大神们可以出个小白部署教程吗?谢谢
010000 + 1 + 1 这个代码是个硬菜,学习收获良多
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
快乐的小驹 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

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

推荐
ZX0228 发表于 2025-4-14 18:09
klmt567 发表于 2025-4-14 17:01
老哥用的什么ai,我之前用ai搞东西,各种报错,修改一下就换地方报错

用deepseek一点一点搞,很简单啊  啥问题描述清楚  报错发给ai 修改就好了,我算是比0基础强一点,只会一点python,前端和小程序基本上算是0基础,用deepseek 给我媳妇搞了个小程序 网页端 服务端 小程序 ,从开发  到宝塔部署  再到域名备案  然后ssl 基本上都是用deepseek解决的,现在小程序基本上线了  就差备案卡在管局 估计要等1星期
推荐
 楼主| 尖叫的体毛 发表于 2025-4-14 17:03 |楼主
klmt567 发表于 2025-4-14 17:01
老哥用的什么ai,我之前用ai搞东西,各种报错,修改一下就换地方报错

deepseek
现在基本都是用这个吧
报错的话很正常,看得懂一点点或者问AI,一般都没啥问题
我也遇到报错很多次,把报错的点在问AI就好了
3#
klmt567 发表于 2025-4-14 17:01
老哥用的什么ai,我之前用ai搞东西,各种报错,修改一下就换地方报错
4#
makaay 发表于 2025-4-14 17:05
这个功能太实用了,终于可以解决会议室管理问题了。感谢分享!!!
5#
rhci 发表于 2025-4-14 17:14
大神,基本运行正常,不过我这边出来像是简版的,没有图像,不知道是不是路径不对,还是啥问题,就是没皮肤
6#
 楼主| 尖叫的体毛 发表于 2025-4-14 17:16 |楼主
rhci 发表于 2025-4-14 17:14
大神,基本运行正常,不过我这边出来像是简版的,没有图像,不知道是不是路径不对,还是啥问题,就是没皮肤

没皮肤啥意思,截个图看看最好
7#
rhci 发表于 2025-4-14 17:19
尖叫的体毛 发表于 2025-4-14 17:16
没皮肤啥意思,截个图看看最好


就是这个样子的
8#
懒洋洋的池塘 发表于 2025-4-14 17:21
这个功能太实用了,终于可以解决会议室管理问题了。
9#
 楼主| 尖叫的体毛 发表于 2025-4-14 17:25 |楼主
rhci 发表于 2025-4-14 17:19
就是这个样子的

知识盲区了哈哈
看有没有大神知道吧

我在新电脑上设置的也是没问题的
10#
rhci 发表于 2025-4-14 17:27
尖叫的体毛 发表于 2025-4-14 17:25
知识盲区了哈哈
看有没有大神知道吧

找到原因了,浏览器适配的问题,谷歌浏览器就没问题,但是用edge就出这问题了。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2025-5-21 08:08

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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