上篇已经以用户注册登录为例创建了一个完整的demo,这篇继续在原有的基础上添加日程管理模块的代码,这也是整个项目中最核心的代码。
前言
上篇已经以用户注册登录为例创建了一个完整的demo,这篇继续在原有的基础上添加日程管理模块的代码,这也是整个项目中最核心的代码。
日程管理的实现
按照MVC的模式一般是:模型–>视图–>控制器的顺序
创建模型
模型的创建其实在上篇中已经完成:
Event.py:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from app import db
from app.model.User import User
from sqlalchemy.ext.hybrid import hybrid_property
class Event ( db . Model ):
__tablename__ = 'events'
id = db . Column ( db . Integer , primary_key = True )
user_id = db . Column ( db . Integer , db . ForeignKey ( User . id , ondelete = 'CASCADE' ), nullable = False )
title = db . Column ( db . String ( 255 ), nullable = False )
start_date = db . Column ( db . Date , nullable = False )
event_time = db . Column ( db . Time )
end_date = db . Column ( db . Date )
location = db . Column ( db . String ( 255 ))
description = db . Column ( db . String ( 255 ))
repeat = db . Column ( db . String ( 255 ), nullable = False , default = "none" ) # Text field for custom repeat types
reminder_type = db . Column ( db . String ( 255 ), nullable = False , default = "none" )
reminder_time = db . Column ( db . Float , nullable = True , default = 0 )
@hybrid_property
def duration ( self ):
return self . end_date - self . start_date
def __init__ ( self , user_id , title , start_date , event_time , end_date , location , description , reminder_time ,
repeat , reminder_type ):
self . user_id = user_id
self . title = title
self . start_date = start_date
self . event_time = event_time
self . end_date = end_date
self . location = location
self . description = description
self . repeat = repeat
self . reminder_type = reminder_type
self . reminder_time = reminder_time
def __repr__ ( self ):
return '<Event %r >' % self . title
创建视图
考虑到业务需求,主要是对Event表进行CRUD操作,所以在event
蓝图下创建了四个路由:
创建app/views/event_view.py
1
2
3
4
5
6
7
8
9
10
11
# event_view.py
from flask import Blueprint
from app.controller import event_controller # 导入 event_controller 模块
event_blueprint = Blueprint ( 'event' , __name__ )
# 将视图函数与蓝图关联
event_blueprint . route ( '/event_list' )( event_controller . show_event )
event_blueprint . route ( '/create_event' , methods = [ 'GET' , 'POST' ])( event_controller . create_event )
event_blueprint . route ( '/delete_event/<int:event_id>' , methods = [ 'POST' ])( event_controller . delete_event )
event_blueprint . route ( '/edit_event/<int:event_id>' , methods = [ 'GET' , 'POST' ])( event_controller . edit_event )
创建控制器
明确了视图,现在只需要完成对Event表的CRUD即可,创建app/controller/event_controller.py
查询事件
使用flask-login插件管理用户,利用@login_required装饰器获取当前登录用户的id。创建一个动态生成事件的函数get_user_events
按照用户设置的规则动态生成将要在前端显示的事件,这样可以够支持用户设置特点频率的事件而且能避免数据库的负担过大。编写一个逻辑检查过期的事件并同未过期的事件一并返回。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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
@login_required
def show_event ():
user_id = current_user . id # 获取当前登录用户的ID
today_events , expired_events = get_user_events ( user_id )
return render_template ( 'event_list.html' , events = today_events , expired_events = expired_events )
def get_user_events ( user_id ):
"""
查询当前用户的所有事件,并根据事件的重复规则生成今天的事件列表和过期事件列表。
Args:
user_id (int): 用户ID
Returns:
tuple: 包含今天的事件列表和过期事件列表的元组
"""
# 查询当前用户的所有事件
events = Event . query . filter_by ( user_id = user_id ) . all ()
today = datetime . now () . date () # 获取当前日期
today_events = []
expired_events = []
for event in events :
# 如果事件过期,将其添加到过期事件列表中
if event . end_date < today :
expired_events . append ( event )
continue
# 如果事件不是重复事件,将其添加到今天事件列表中
if event . repeat == "none" and today <= event . end_date :
today_events . append ( event )
# 如果事件是重复事件,动态生成后将其添加到今天事件列表中
else :
start_date = event . start_date
end_date = event . end_date
if event . repeat == "daily" :
current_date = start_date
while current_date <= end_date :
if current_date >= today :
new_event = generate_repeat_event ( event , current_date )
today_events . append ( new_event )
break
current_date += timedelta ( days = 1 )
elif event . repeat == "weekly" :
if end_date - today < timedelta ( days = 7 ):
expired_events . append ( event )
continue
current_date = start_date
while current_date <= end_date :
if current_date >= today :
last_week_event = generate_repeat_event ( event , current_date )
today_events . append ( last_week_event )
break
current_date += timedelta ( weeks = 1 )
elif event . repeat == "monthly" :
if end_date - today < timedelta ( days = 30 ):
expired_events . append ( event )
continue
current_date = start_date
while current_date <= end_date :
if current_date >= today :
last_month_event = generate_repeat_event ( event , current_date )
today_events . append ( last_month_event )
break
current_date += timedelta ( days = 30 )
return today_events , expired_events
# 创建一个函数,用于生成重复事件
def generate_repeat_event ( event , current_date ):
new_event = Event (
user_id = event . user_id ,
title = event . title ,
start_date = current_date ,
end_date = current_date ,
event_time = event . event_time ,
location = event . location ,
description = event . description ,
repeat = event . repeat ,
reminder_type = event . reminder_type ,
reminder_time = event . reminder_time
)
new_event . id = event . id # 设置新事件的ID为原事件的ID
return new_event ```
### 创建事件
在用户提交表单之前 , 使用表单验证能够有效规范数据库在forms . py上加入对Event的表单验证 :
``` python
# forms.py
from flask_wtf import FlaskForm
from wtforms import StringField , PasswordField , validators , SubmitField , ValidationError , DateField , TimeField
class RegisterForm ( FlaskForm ):
name = StringField ( '用户名' , [ validators . DataRequired ( "用户名不能为空" )])
email = StringField ( '邮箱' , [ validators . DataRequired ( "邮箱不能为空" ), validators . Email ( "无效的邮箱地址" )])
phone = StringField ( '电话' )
password = PasswordField ( '密码' , [
validators . DataRequired ( "密码不能为空" ),
validators . Length ( min = 8 , message = "密码长度至少 8 个字符" )
])
confirm_password = PasswordField ( '确认密码' , [
validators . DataRequired ( "请再次输入密码" ),
validators . EqualTo ( 'password' , message = '两次密码不匹配' )
])
class LoginForm ( FlaskForm ):
email = StringField ( '邮箱' , [ validators . DataRequired ( "邮箱不能为空" ), validators . Email ( "无效的邮箱地址" )])
password = PasswordField ( '密码' , [ validators . DataRequired ( "密码不能为空" )])
remember = StringField ( '记住我' )
class EventForm ( FlaskForm ):
title = StringField ( '标题' , validators = [ validators . DataRequired (), validators . Length ( max = 255 )])
start_date = DateField ( '开始日期' , format = '%Y-%m- %d ' , validators = [ validators . DataRequired ()])
event_time = TimeField ( '事件时间' , format = '%H:%M' )
end_date = DateField ( '结束时间' , format = '%Y-%m- %d ' )
location = StringField ( '地点' , validators = [ validators . Length ( max = 255 )])
description = StringField ( '描述' , validators = [ validators . Length ( max = 255 )])
repeat = StringField ( '重复' )
reminder_type = StringField ( '提醒类型' , validators = [ validators . DataRequired ()])
reminder_time = StringField ( '提醒时间' )
submit = SubmitField ( 'Submit' ) # 添加这一行来定义 submit 字段
# 如果结束时间小于或等于开始时间,则引发验证错误。
def validate_end_time ( self , field ):
if field . data <= self . start_date . data :
raise ValidationError ( 'End time must be greater than start time' )
编写创建事件逻辑:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@login_required
def create_event ():
"""
创建事件并保存到数据库。
return: 重定向到事件列表页面或其他适当的页面
"""
form = EventForm () # 使用您的事件表单来接收用户输入
if not form . validate_on_submit ():
for field , errors in form . errors . items ():
for error in errors :
print ( f "字段 { field } 中的错误: { error } " )
if form . validate_on_submit ():
# 获取用户输入的事件信息
title = form . title . data
event_time = form . event_time . data
start_date = form . start_date . data
end_date = form . end_date . data
location = form . location . data
description = form . description . data
repeat = form . repeat . data # 从表单获取重复类型
reminder_type = form . reminder_type . data
reminder_time = form . reminder_time . data
# 创建事件对象并保存到数据库
event = Event (
user_id = current_user . id , # 使用当前登录用户的 ID
title = title ,
event_time = event_time ,
start_date = start_date ,
end_date = end_date ,
location = location ,
description = description ,
repeat = repeat , # 设置事件的重复类型
reminder_type = reminder_type ,
reminder_time = reminder_time
)
db . session . add ( event )
db . session . commit ()
flash ( '事件创建成功' , 'success' )
return redirect ( url_for ( 'event.show_event' )) # 重定向到事件列表页面或其他适当的页面
return render_template ( 'create_event.html' , form = form )
删除事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@login_required
def delete_event ( event_id ):
# 查询要删除的事件
event = Event . query . get ( event_id )
# 检查事件是否存在并属于当前用户
if event and event . user_id == current_user . id :
db . session . delete ( event )
db . session . commit ()
flash ( '事件删除成功' , 'success' )
else :
flash ( '无法删除事件' , 'error' )
return redirect ( url_for ( 'event.show_event' ))
编辑事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@login_required
def edit_event ( event_id ):
# 查询要编辑的事件
event = Event . query . get ( event_id )
# 检查事件是否存在并属于当前用户
if not event or event . user_id != current_user . id :
flash ( '无法编辑事件' , 'error' )
return redirect ( url_for ( 'event.show_event' ))
form = EventForm ( obj = event ) # 使用事件对象填充表单
if form . validate_on_submit ():
# 更新事件信息
event . title = form . title . data
event . event_time = form . event_time . data
event . start_date = form . start_date . data
event . end_date = form . end_date . data
event . location = form . location . data
event . description = form . description . data
event . repeat = form . repeat . data # 从表单获取重复类型
event . reminder_type = form . reminder_type . data
event . reminder_time = form . reminder_time . data
db . session . commit ()
flash ( '事件更新成功' , 'success' )
return redirect ( url_for ( 'event.show_event' ))
return render_template ( 'edit_event.html' , form = form )
前端页面
完成了后端的逻辑,接下来只需要通过jinja2语法创建模板即可。由于html代码可读性差,以下使用项目的初始demo来说明。demo中只有jinja2接口,基本上没有任何样式,但是代码可读性强。
构建 /event/event_list
对应的页面
创建模板app/templates/event_list.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<!DOCTYPE html>
< html lang = "en" >
< head >
< title > 事件列表</ title >
</ head >
< body >
< h1 > 事件列表</ h1 >
< ul >
<!--显示待执行的事件-->
{% for event in events %}
< li >
< h2 > {{ event.title }}</ h2 >
< p >< strong > 日期:</ strong > {{ event.start_date }} - {{ event.end_date }}</ p >
< p >< strong > 时间:</ strong > {{ event.event_time }}</ p >
< p >< strong > 地点:</ strong > {{ event.location }}</ p >
< p >< strong > 描述:</ strong > {{ event.description }}</ p >
< p >< strong > 重复:</ strong > {{ event.repeat }}</ p >
< p >< strong > 提醒类型:</ strong > {{ event.reminder_type }}</ p >
{% with days=event.reminder_time // (24 * 60), hours=(event.reminder_time % (24 * 60)) // 60, minutes=(event.reminder_time % 60) %}
< p >< strong > 提醒时间:</ strong > {{ days }} 天 {{ hours }} 小时 {{ minutes }} 分钟</ p >
{% endwith %}
< a href = "{{ url_for('event.edit_event', event_id=event.id) }}" > 编辑</ a >
< form method = "post" action = "{{ url_for('event.delete_event', event_id=event.id) }}" >
< input type = "submit" value = "删除" >
</ form >
</ li >
{% endfor %}
<!--显示过期的事件-->
{% for event in expired_events %}
< li style = "color: gray" >
< h2 > {{ event.title }}</ h2 >
< p style = "color: red" >< strong > 日期:</ strong > {{ event.start_date }} - {{ event.end_date }}</ p >
< p >< strong > 时间:</ strong > {{ event.event_time }}</ p >
< p >< strong > 地点:</ strong > {{ event.location }}</ p >
< p >< strong > 描述:</ strong > {{ event.description }}</ p >
< p >< strong > 重复:</ strong > {{ event.repeat }}</ p >
< p >< strong > 提醒类型:</ strong > {{ event.reminder_type }}</ p >
{% with days=event.reminder_time // (24 * 60), hours=(event.reminder_time % (24 * 60)) // 60, minutes=(event.reminder_time % 60) %}
< p >< strong > 提醒时间:</ strong > {{ days }} 天 {{ hours }} 小时 {{ minutes }} 分钟</ p >
{% endwith %}
< a href = "{{ url_for('event.edit_event', event_id=event.id) }}" > 编辑</ a >
< form method = "post" action = "{{ url_for('event.delete_event', event_id=event.id) }}" >
< input type = "submit" value = "删除" >
</ form >
</ li >
{% endfor %}
</ ul >
< a href = "{{ url_for('event.create_event') }}" > 创建事件</ a >
</ body >
</ html >
构建 /event/creat_event
对应的页面
创建模板 app/templates/create_event.html
,注意需要在提交表单前加上{{ form.hidden_tag() }}
保证通过表单验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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
<!DOCTYPE html>
< html lang = "en" >
< head >
< title > Create Event</ title >
< link rel = "stylesheet" href = "{{ url_for('static', filename='css/http_cdn.jsdelivr.net_npm_flatpickr_dist_flatpickr.css') }}" >
< script src = "{{ url_for('static', filename='js/http_cdn.jsdelivr.net_npm_flatpickr.js') }}" ></ script >
</ head >
< body >
< h1 > Create Event</ h1 >
< form onsubmit = "combineAndSubmit()" method = "POST" >
{{ form.hidden_tag() }}
< div >
{{ form.title.label(class="form-label") }}
{{ form.title(class="form-control") }}
{% for error in form.title.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.start_date.label(class="form-label") }}
{{ form.start_date(class="form-control flatpickr",id="start_date") }}
{% for error in form.start_date.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.event_time.label(class="form-label") }}
{{ form.event_time(class="form-control flatpickr",id="event_time") }}
{% for error in form.event_time.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.end_date.label(class="form-label") }}
{{ form.end_date(class="form-control, flatpickr",id="end_date") }}
{% for error in form.end_date.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.location.label(class="form-label") }}
{{ form.location(class="form-control") }}
{% for error in form.location.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.description.label(class="form-label") }}
{{ form.description(class="form-control") }}
{% for error in form.description.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
< label for = "repeatSelect" > {{ form.repeat.label(class="form-label") }}</ label >
< select name = "repeat" id = "repeatSelect" class = "form-control" >
< option value = "none" > 无</ option >
< option value = "daily" > 每天</ option >
< option value = "weekly" > 每周</ option >
< option value = "month" > 每月</ option >
</ select >
{% for error in form.repeat.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
< label for = "reminder_type" > {{ form.reminder_type.label(class="form-label") }}</ label >
< select name = "reminder_type" id = "reminder_type" class = "form-control" >
< option value = "none" > 无</ option >
< option value = "email" > 邮箱</ option >
< option value = "phone" > 手机</ option >
< option value = "pepper" > 机器人</ option >
</ select >
{% for error in form.reminder_type.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.reminder_time.label(class="form-label") }}
< input type = "button" value = "设置提醒" onclick = "showReminderOptions()" >
{% for error in form.reminder_time.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div id = "reminderOptions" style = "display: none;" >
< label for = "daysInput" > 天数:</ label >
< input type = "number" id = "daysInput" name = "daysInput" min = "0" >
< br >
< label for = "hoursInput" > 小时:</ label >
< select id = "hoursInput" name = "hoursInput" >
<!-- 使用 JavaScript 动态生成选项 -->
</ select >
< br >
< label for = "minutesInput" > 分钟:</ label >
< select id = "minutesInput" name = "minutesInput" >
<!-- 使用 JavaScript 动态生成选项 -->
</ select >
</ div >
< div >
<!-- 隐藏的input元素用于存储提醒时间 -->
< input type = "hidden" name = "reminder_time" id = "reminder_time" value = "" >
</ div >
< div >
{{ form.submit()}}
</ div >
</ form >
< script >
flatpickr ( '#start_date' , {
enableTime : false ,
dateFormat : "Y-m-d" ,
});
flatpickr ( '#event_time' , {
enableTime : true ,
noCalendar : true , // 禁用日期选择
time_24hr : true , // 使用24小时制
dateFormat : "H:i" ,
});
flatpickr ( '#end_date' , {
enableTime : false ,
dateFormat : "Y-m-d" ,
});
</ script >
< script >
function populateOptions ( element , max ) {
for ( let i = 0 ; i <= max ; i ++ ) {
const option = document . createElement ( 'option' );
option . value = i ;
option . text = i ;
element . appendChild ( option );
}
}
// 动态生成小时和分钟的选项
populateOptions ( document . getElementById ( 'hoursInput' ), 24 );
populateOptions ( document . getElementById ( 'minutesInput' ), 60 );
function showReminderOptions () {
// 显示设置提醒时间的选项
document . getElementById ( 'reminderOptions' ). style . display = 'block' ;
}
function combineAndSubmit () {
var daysInput = parseFloat ( document . getElementById ( 'daysInput' ). value ) || 0 ;
var hoursInput = parseFloat ( document . getElementById ( 'hoursInput' ). value ) || 0 ;
var minutesInput = parseFloat ( document . getElementById ( 'minutesInput' ). value ) || 0 ;
// 转换为分钟
var totalMinutes = daysInput * 24 * 60 + hoursInput * 60 + minutesInput ;
// 将totalMinutes设置到表单的form.reminder_time字段
document . getElementById ( 'reminder_time' ). value = totalMinutes ;
// 可以将表单提交到服务器或进行其他操作
alert ( "总时间(分钟):" + totalMinutes );
}
</ script >
</ body >
</ html >
构建 /event/edit_event/
对应的页面
创建模板 app/templates/edit_event.html
,/event/delete_event/
路由没有页面,而是通过按钮来触发并删除事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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
<!DOCTYPE html>
< html lang = "en" >
< head >
< title > Create Event</ title >
< link rel = "stylesheet" href = "{{ url_for('static', filename='css/http_cdn.jsdelivr.net_npm_flatpickr_dist_flatpickr.css') }}" >
< script src = "{{ url_for('static', filename='js/http_cdn.jsdelivr.net_npm_flatpickr.js') }}" ></ script >
</ head >
< body >
< h1 > Create Event</ h1 >
< form onsubmit = "combineAndSubmit()" method = "POST" >
{{ form.hidden_tag() }}<!DOCTYPE html>
< html lang = "en" >
< head >
< title > Edit Event</ title >
< link rel = "stylesheet" href = "{{ url_for('static', filename='css/http_cdn.jsdelivr.net_npm_flatpickr_dist_flatpickr.css') }}" >
< script src = "{{ url_for('static', filename='js/http_cdn.jsdelivr.net_npm_flatpickr.js') }}" ></ script >
</ head >
< body >
< h1 > Edit Event</ h1 >
< form onsubmit = "combineAndSubmit()" method = "POST" >
{{ form.hidden_tag() }}
< div >
{{ form.title.label(class="form-label") }}
{{ form.title(class="form-control") }}
{% for error in form.title.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.start_date.label(class="form-label") }}
{{ form.start_date(class="form-control flatpickr",id="start_date") }}
{% for error in form.start_date.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.event_time.label(class="form-label") }}
{{ form.event_time(class="form-control flatpickr",id="event_time") }}
{% for error in form.event_time.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.end_date.label(class="form-label") }}
{{ form.end_date(class="form-control, flatpickr",id="end_date") }}
{% for error in form.end_date.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.location.label(class="form-label") }}
{{ form.location(class="form-control") }}
{% for error in form.location.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.description.label(class="form-label") }}
{{ form.description(class="form-control") }}
{% for error in form.description.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
< label for = "repeatSelect" > {{ form.repeat.label(class="form-label") }}</ label >
< select name = "repeat" id = "repeatSelect" class = "form-control" >
< option value = "none" {% if form . repeat . data = = ' none ' %} selected {% endif %} > 无</ option >
< option value = "daily" {% if form . repeat . data = = ' daily '%} selected {% endif %} > 每天</ option >
< option value = "weekly" {% if form . repeat . data = = ' weekly ' %} selected {% endif %} > 每周</ option >
< option value = "month" {% if form . repeat . data = = ' month ' %} selected {% endif %} > 每月</ option >
</ select >
{% for error in form.repeat.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
< label for = "reminder_type" > {{ form.reminder_type.label(class="form-label") }}</ label >
< select name = "reminder_type" id = "reminder_type" class = "form-control" >
< option value = "none" {% if form . reminder_type . data = = ' none ' %} selected {% endif %} > 无</ option >
< option value = "email" {% if form . reminder_type . data = = ' email ' %} selected {% endif %} > 邮箱</ option >
< option value = "phone" {% if form . reminder_type . data = = ' phone ' %} selected {% endif %} > 手机</ option >
< option value = "pepper" {% if form . reminder_type . data = = ' pepper ' %} selected {% endif %} > 机器人</ option >
</ select >
{% for error in form.reminder_type.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.reminder_time.label(class="form-label") }}
{{ form.reminder_time(class="form-control",style="display: none;") }}
< input type = "button" value = "设置提醒" onclick = "showReminderOptions()" >
{% for error in form.reminder_time.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div id = "reminderOptions" style = "display: none;" >
< label for = "daysInput" > 天数:</ label >
< input type = "number" id = "daysInput" name = "daysInput" min = "0" >
< br >
< label for = "hoursInput" > 小时:</ label >
< select id = "hoursInput" name = "hoursInput" >
<!-- 使用 JavaScript 动态生成选项 -->
</ select >
< br >
< label for = "minutesInput" > 分钟:</ label >
< select id = "minutesInput" name = "minutesInput" >
<!-- 使用 JavaScript 动态生成选项 -->
</ select >
</ div >
< div >
<!-- 隐藏的input元素用于存储提醒时间 -->
< input type = "hidden" name = "reminder_time" id = "reminder_time" value = "" >
</ div >
< div >
{{ form.submit()}}
</ div >
</ form >
< script >
flatpickr ( '#start_date' , {
enableTime : false ,
dateFormat : "Y-m-d" ,
});
flatpickr ( '#event_time' , {
enableTime : true ,
noCalendar : true , // 禁用日期选择
time_24hr : true , // 使用24小时制
dateFormat : "H:i" ,
});
flatpickr ( '#end_date' , {
enableTime : false ,
dateFormat : "Y-m-d" ,
});
</ script >
< script >
function populateOptions ( element , max ) {
for ( let i = 0 ; i <= max ; i ++ ) {
const option = document . createElement ( 'option' );
option . value = i ;
option . text = i ;
element . appendChild ( option );
}
}
// 动态生成小时和分钟的选项
populateOptions ( document . getElementById ( 'hoursInput' ), 24 );
populateOptions ( document . getElementById ( 'minutesInput' ), 60 );
var isReminderChanged = false ; // 添加标志变量,用于判断是否更改了提醒时间
function showReminderOptions () {
// 显示提醒选项时将标志变量设置为 true
isReminderChanged = true ;
var reminderTime = parseFloat ( document . getElementById ( "reminder_time" ). value );
// 计算天数、小时和分钟
var days = Math . floor ( reminderTime / ( 24 * 60 ));
var hours = Math . floor (( reminderTime % ( 24 * 60 )) / 60 );
var minutes = reminderTime % 60 ;
// 更新隐藏的三个选项框的值
document . getElementById ( "daysInput" ). value = days ;
document . getElementById ( "hoursInput" ). value = hours ;
document . getElementById ( "minutesInput" ). value = minutes ;
// 显示设置提醒时间的选项
document . getElementById ( 'reminderOptions' ). style . display = 'block' ;
}
function combineAndSubmit () {
if ( isReminderChanged ) { // 只有在提醒时间发生更改时才执行以下逻辑
var daysInput = parseFloat ( document . getElementById ( 'daysInput' ). value ) || 0 ;
var hoursInput = parseFloat ( document . getElementById ( 'hoursInput' ). value ) || 0 ;
var minutesInput = parseFloat ( document . getElementById ( 'minutesInput' ). value ) || 0 ;
// 转换为分钟
var totalMinutes = daysInput * 24 * 60 + hoursInput * 60 + minutesInput ;
// 将totalMinutes设置到表单的form.reminder_time字段
document . getElementById ( 'reminder_time' ). value = totalMinutes ;
// 可以将表单提交到服务器或进行其他操作
alert ( "总时间(分钟):" + totalMinutes );
}
// 重置标志变量
isReminderChanged = false ;
}
</ script >
</ body >
</ html >
< div >
{{ form.title.label(class="form-label") }}
{{ form.title(class="form-control") }}
{% for error in form.title.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.start_date.label(class="form-label") }}
{{ form.start_date(class="form-control flatpickr",id="start_date") }}
{% for error in form.start_date.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.event_time.label(class="form-label") }}
{{ form.event_time(class="form-control flatpickr",id="event_time") }}
{% for error in form.event_time.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.end_date.label(class="form-label") }}
{{ form.end_date(class="form-control, flatpickr",id="end_date") }}
{% for error in form.end_date.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.location.label(class="form-label") }}
{{ form.location(class="form-control") }}
{% for error in form.location.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.description.label(class="form-label") }}
{{ form.description(class="form-control") }}
{% for error in form.description.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
< label for = "repeatSelect" > {{ form.repeat.label(class="form-label") }}</ label >
< select name = "repeat" id = "repeatSelect" class = "form-control" >
< option value = "none" > 无</ option >
< option value = "daily" > 每天</ option >
< option value = "weekly" > 每周</ option >
< option value = "month" > 每月</ option >
</ select >
{% for error in form.repeat.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
< label for = "reminder_type" > {{ form.reminder_type.label(class="form-label") }}</ label >
< select name = "reminder_type" id = "reminder_type" class = "form-control" >
< option value = "none" > 无</ option >
< option value = "email" > 邮箱</ option >
< option value = "phone" > 手机</ option >
< option value = "pepper" > 机器人</ option >
</ select >
{% for error in form.reminder_type.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div >
{{ form.reminder_time.label(class="form-label") }}
< input type = "button" value = "设置提醒" onclick = "showReminderOptions()" >
{% for error in form.reminder_time.errors %}
< span style = "color: red;" > {{ error }}</ span >
{% endfor %}
</ div >
< div id = "reminderOptions" style = "display: none;" >
< label for = "daysInput" > 天数:</ label >
< input type = "number" id = "daysInput" name = "daysInput" min = "0" >
< br >
< label for = "hoursInput" > 小时:</ label >
< select id = "hoursInput" name = "hoursInput" >
<!-- 使用 JavaScript 动态生成选项 -->
</ select >
< br >
< label for = "minutesInput" > 分钟:</ label >
< select id = "minutesInput" name = "minutesInput" >
<!-- 使用 JavaScript 动态生成选项 -->
</ select >
</ div >
< div >
<!-- 隐藏的input元素用于存储提醒时间 -->
< input type = "hidden" name = "reminder_time" id = "reminder_time" value = "" >
</ div >
< div >
{{ form.submit()}}
</ div >
</ form >
< script >
flatpickr ( '#start_date' , {
enableTime : false ,
dateFormat : "Y-m-d" ,
});
flatpickr ( '#event_time' , {
enableTime : true ,
noCalendar : true , // 禁用日期选择
time_24hr : true , // 使用24小时制
dateFormat : "H:i" ,
});
flatpickr ( '#end_date' , {
enableTime : false ,
dateFormat : "Y-m-d" ,
});
</ script >
< script >
function populateOptions ( element , max ) {
for ( let i = 0 ; i <= max ; i ++ ) {
const option = document . createElement ( 'option' );
option . value = i ;
option . text = i ;
element . appendChild ( option );
}
}
// 动态生成小时和分钟的选项
populateOptions ( document . getElementById ( 'hoursInput' ), 24 );
populateOptions ( document . getElementById ( 'minutesInput' ), 60 );
function showReminderOptions () {
// 显示设置提醒时间的选项
document . getElementById ( 'reminderOptions' ). style . display = 'block' ;
}
function combineAndSubmit () {
var daysInput = parseFloat ( document . getElementById ( 'daysInput' ). value ) || 0 ;
var hoursInput = parseFloat ( document . getElementById ( 'hoursInput' ). value ) || 0 ;
var minutesInput = parseFloat ( document . getElementById ( 'minutesInput' ). value ) || 0 ;
// 转换为分钟
var totalMinutes = daysInput * 24 * 60 + hoursInput * 60 + minutesInput ;
// 将totalMinutes设置到表单的form.reminder_time字段
document . getElementById ( 'reminder_time' ). value = totalMinutes ;
// 可以将表单提交到服务器或进行其他操作
alert ( "总时间(分钟):" + totalMinutes );
}
</ script >
</ body >
</ html >
效果呈现
注:以下效果图的html代码并非以上的代码,而是通过优化后的效果
/event/event_list
/event/creat_event
/event/edit_event/