task-manager 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.md +4 -0
- data/Rakefile +27 -0
- data/app/assets/images/task-manager/icons/add.png +0 -0
- data/app/assets/images/task-manager/icons/delete.png +0 -0
- data/app/assets/images/task-manager/icons/edit.png +0 -0
- data/app/assets/javascripts/task-manager/application.js +43 -0
- data/app/assets/javascripts/task-manager/extjs/app/controller/Plans.js +359 -0
- data/app/assets/javascripts/task-manager/extjs/app/controller/Tasks.js +56 -0
- data/app/assets/javascripts/task-manager/extjs/app/helper/application_helper.js +24 -0
- data/app/assets/javascripts/task-manager/extjs/app/model/Assignee.js +19 -0
- data/app/assets/javascripts/task-manager/extjs/app/model/Plan.js +195 -0
- data/app/assets/javascripts/task-manager/extjs/app/model/Task.js +23 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Assignees.js +53 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/AssigneesTree.js +3 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Booleans.js +9 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Days.js +38 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Hours.js +31 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Minutes.js +67 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Months.js +19 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Plans.js +6 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/QuarterlyMonths.js +10 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Statuses.js +11 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Tasks.js +6 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/Types.js +12 -0
- data/app/assets/javascripts/task-manager/extjs/app/store/WeekDays.js +14 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/AssignablesWindow.js +23 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/Edit.js +189 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/EditWindow.js +21 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/Grid.js +92 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/Index.js +24 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/New.js +190 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/Search.js +132 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/SelectAssignables.js +22 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/SelectAssignablesGrid.js +22 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/SelectAssignablesTree.js +9 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/plan/Window.js +21 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/task/Grid.js +62 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/task/Index.js +21 -0
- data/app/assets/javascripts/task-manager/extjs/app/view/task/Search.js +148 -0
- data/app/assets/javascripts/task-manager/extjs/lib/ux/MultiSelectablePagingGrid.js +20 -0
- data/app/assets/javascripts/task-manager/extjs/lib/ux/RowExpander.js +230 -0
- data/app/assets/stylesheets/task-manager/application.css.scss +13 -0
- data/app/assets/stylesheets/task-manager/extjs.css.scss +43 -0
- data/app/controllers/task_manager/api/v1/plans_controller.rb +251 -0
- data/app/controllers/task_manager/api/v1/tasks_controller.rb +82 -0
- data/app/controllers/task_manager/application_controller.rb +4 -0
- data/app/helpers/task_manager/application_helper.rb +4 -0
- data/app/models/task_manager/assignable.rb +10 -0
- data/app/models/task_manager/callable.rb +10 -0
- data/app/models/task_manager/plan.rb +114 -0
- data/app/models/task_manager/task.rb +81 -0
- data/app/serializers/task_manager/plan_serializer.rb +8 -0
- data/app/serializers/task_manager/task_serializer.rb +8 -0
- data/app/views/layouts/task-manager/application.html.erb +14 -0
- data/config/routes.rb +8 -0
- data/db/migrate/20121102054723_setup_hstore.rb +9 -0
- data/db/migrate/20121102055137_create_task_manager_plans.rb +16 -0
- data/db/migrate/20121102142657_create_task_manager_assignables.rb +13 -0
- data/db/migrate/20121102150720_create_task_manager_callables.rb +13 -0
- data/db/migrate/20121105170602_create_task_manager_tasks.rb +18 -0
- data/lib/task-manager.rb +37 -0
- data/lib/task-manager/api_constraints.rb +12 -0
- data/lib/task-manager/deadline_calculator.rb +22 -0
- data/lib/task-manager/deadline_validator.rb +27 -0
- data/lib/task-manager/engine.rb +5 -0
- data/lib/task-manager/version.rb +3 -0
- data/lib/tasks/task-manager_tasks.rake +4 -0
- metadata +327 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
Ext.define('TM.controller.Tasks', {
|
2
|
+
extend: 'Ext.app.Controller',
|
3
|
+
|
4
|
+
views: ['task.Index'],
|
5
|
+
|
6
|
+
refs: [{
|
7
|
+
ref: 'searchForm',
|
8
|
+
selector: 'task_search'
|
9
|
+
}],
|
10
|
+
|
11
|
+
init: function() {
|
12
|
+
this.control({
|
13
|
+
'task_search button[action="query"]': {
|
14
|
+
click: this.onQueryClick
|
15
|
+
},
|
16
|
+
'task_search button[action="reset"]': {
|
17
|
+
click: this.onSearchResetClick
|
18
|
+
},
|
19
|
+
'task_grid button[action="delete"]': {
|
20
|
+
click: this.onDeleteClick
|
21
|
+
}
|
22
|
+
});
|
23
|
+
},
|
24
|
+
|
25
|
+
onQueryClick: function(btn) {
|
26
|
+
var params = this.getSearchForm().getValues();
|
27
|
+
Ext.getStore('TM.store.Tasks').load({ params: params });
|
28
|
+
},
|
29
|
+
|
30
|
+
onSearchResetClick: function(btn) {
|
31
|
+
this.getSearchForm().getForm().reset();
|
32
|
+
},
|
33
|
+
|
34
|
+
onDeleteClick: function(btn) {
|
35
|
+
var select = btn.up('task_grid').getSelectionModel().getSelection()[0];
|
36
|
+
if(select == null) {
|
37
|
+
Ext.Msg.alert('提示','请选择要删除的计划任务');
|
38
|
+
return;
|
39
|
+
}
|
40
|
+
|
41
|
+
Ext.Msg.confirm('提示','您确认要删除选中的计划任务吗?', function(b){
|
42
|
+
if(b != 'yes') return;
|
43
|
+
|
44
|
+
var selected = btn.up('task_grid').getSelectionModel().getSelection();
|
45
|
+
Ext.each(selected, function(s){
|
46
|
+
this.callParent(arguments);
|
47
|
+
|
48
|
+
if(this.store) this.store.remove(this);
|
49
|
+
});
|
50
|
+
});
|
51
|
+
},
|
52
|
+
|
53
|
+
index: function() {
|
54
|
+
this.render('TM.view.task.Index');
|
55
|
+
}
|
56
|
+
});
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Ext.define('TM.helper.ApplicationHelper', {
|
2
|
+
translateType: function(t) {
|
3
|
+
var translations = {
|
4
|
+
yearly: '年计划',
|
5
|
+
quarterly: '季计划',
|
6
|
+
monthly: '月计划',
|
7
|
+
weekly: '周计划',
|
8
|
+
daily: '日计划'
|
9
|
+
};
|
10
|
+
|
11
|
+
return translations[t];
|
12
|
+
},
|
13
|
+
|
14
|
+
translateStatus: function(s) {
|
15
|
+
var translations = {
|
16
|
+
new: '新建',
|
17
|
+
in_process: '进行中',
|
18
|
+
expired: '已过期',
|
19
|
+
finished: '已完成'
|
20
|
+
};
|
21
|
+
|
22
|
+
return translations[s];
|
23
|
+
}
|
24
|
+
});
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Ext.define('TM.model.Assignee', {
|
2
|
+
extend: 'Ext.data.Model',
|
3
|
+
|
4
|
+
fields: [
|
5
|
+
{ name: 'id', type: 'int' },
|
6
|
+
{ name: 'name' },
|
7
|
+
{ name: 'class_name' },
|
8
|
+
{ name: 'parent_id', type: 'int' }
|
9
|
+
],
|
10
|
+
|
11
|
+
proxy: {
|
12
|
+
type: 'rest',
|
13
|
+
url: '/assignees.json',
|
14
|
+
reader: {
|
15
|
+
root: 'assignees',
|
16
|
+
totalProperty: 'total'
|
17
|
+
}
|
18
|
+
}
|
19
|
+
});
|
@@ -0,0 +1,195 @@
|
|
1
|
+
Ext.define('TM.model.Plan', {
|
2
|
+
extend: 'Ext.data.Model',
|
3
|
+
|
4
|
+
fields: [
|
5
|
+
{ name: 'id', type: 'int' },
|
6
|
+
|
7
|
+
{ name: 'name' },
|
8
|
+
{ name: 'plan_type' },
|
9
|
+
{ name: 'data', type: 'auto' },
|
10
|
+
{ name: 'dataX', convert: function(v, record) {
|
11
|
+
return record.get('data').x;
|
12
|
+
}},
|
13
|
+
{ name: 'dataY', convert: function(v, record) {
|
14
|
+
return record.get('data').y;
|
15
|
+
}},
|
16
|
+
{ name: 'quarterly_month', convert: function(v, record) {
|
17
|
+
if (record.get('plan_type') == 'quarterly') return record.get('data').deadline_month;
|
18
|
+
return null;
|
19
|
+
}},
|
20
|
+
{ name: 'month', convert: function(v, record) {
|
21
|
+
if (record.get('plan_type') == 'yearly') return record.get('data').deadline_month;
|
22
|
+
return null;
|
23
|
+
}},
|
24
|
+
{ name: 'weekly_day', convert: function(v, record) {
|
25
|
+
if (record.get('plan_type') == 'weekly') return record.get('data').deadline_day;
|
26
|
+
return null;
|
27
|
+
}},
|
28
|
+
{ name: 'day', convert: function(v, record) {
|
29
|
+
if (record.get('plan_type') != 'weekly') return record.get('data').deadline_day;
|
30
|
+
return null;
|
31
|
+
}},
|
32
|
+
{ name: 'hour', convert: function(v, record) {
|
33
|
+
return record.get('data').deadline_hour;
|
34
|
+
}},
|
35
|
+
{ name: 'minute', convert: function(v, record) {
|
36
|
+
return record.get('data').deadline_minute;
|
37
|
+
}},
|
38
|
+
{ name: 'autocompletable', type: 'boolean' },
|
39
|
+
|
40
|
+
{ name: 'begin_to_remind', type: 'int' },
|
41
|
+
|
42
|
+
{ name: 'enabled_at', type: 'date' },
|
43
|
+
{ name: 'last_task_created_at', type: 'date' },
|
44
|
+
|
45
|
+
|
46
|
+
{ name: 'created_at', type: 'date' },
|
47
|
+
{ name: 'updated_at', type: 'date' },
|
48
|
+
|
49
|
+
{ name: 'assignees', type: 'auto' }
|
50
|
+
],
|
51
|
+
|
52
|
+
proxy: {
|
53
|
+
type: 'rest',
|
54
|
+
url: '/task-manager/api/plans',
|
55
|
+
reader: {
|
56
|
+
root: 'plans',
|
57
|
+
totalProperty: 'total'
|
58
|
+
}
|
59
|
+
},
|
60
|
+
|
61
|
+
set: function() {
|
62
|
+
if (typeof arguments[0] === 'object') {
|
63
|
+
this.callParent(arguments);
|
64
|
+
|
65
|
+
obj = arguments[0];
|
66
|
+
if (obj.data) {
|
67
|
+
this.set('dataX', obj.data.x);
|
68
|
+
this.set('dataY', obj.data.y);
|
69
|
+
this.set('quarterly_month', obj.data.deadline_month);
|
70
|
+
this.set('month', obj.data.deadline_month);
|
71
|
+
this.set('weekly_day', obj.data.deadline_day);
|
72
|
+
this.set('day', obj.data.deadline_day);
|
73
|
+
this.set('hour', obj.data.deadline_hour);
|
74
|
+
this.set('minute', obj.data.deadline_minute);
|
75
|
+
}
|
76
|
+
} else {
|
77
|
+
this.callParent(arguments);
|
78
|
+
}
|
79
|
+
},
|
80
|
+
|
81
|
+
update: function(attrs, opts) {
|
82
|
+
var self = this;
|
83
|
+
var plan = Ext.create('TM.model.Plan', attrs);
|
84
|
+
|
85
|
+
opts = opts || {};
|
86
|
+
var success = opts.success;
|
87
|
+
|
88
|
+
var assignables_attributes = new Array();
|
89
|
+
Ext.Array.forEach(attrs.assignees, function(node, index, assignees) {
|
90
|
+
var record = Ext.getStore('TM.store.Assignees').getById(node.get('id'));
|
91
|
+
assignables_attributes.push({
|
92
|
+
assignee_id: record.get('id'),
|
93
|
+
assignee_type: record.get('class_name')
|
94
|
+
});
|
95
|
+
});
|
96
|
+
|
97
|
+
var callables_attributes = new Array();
|
98
|
+
|
99
|
+
Ext.apply(opts, {
|
100
|
+
url: '/task-manager/api/plans/'+this.get('id'),
|
101
|
+
method: 'PUT',
|
102
|
+
jsonData: {
|
103
|
+
plan: {
|
104
|
+
data: {
|
105
|
+
x: attrs.dataX,
|
106
|
+
y: attrs.dataY,
|
107
|
+
deadline_month: attrs.plan_type == 'quarterly' ? attrs.quarterly_month : (attrs.plan_type == 'yearly' ? attrs.month : null),
|
108
|
+
deadline_day: attrs.plan_type == 'weekly' ? attrs.weekly_day : (attrs.plan_type == 'daily' ? null : attrs.day),
|
109
|
+
deadline_hour: attrs.hour,
|
110
|
+
deadline_minute: attrs.minute
|
111
|
+
},
|
112
|
+
name: attrs.name,
|
113
|
+
plan_type: attrs.plan_type,
|
114
|
+
enabled_at: attrs.enabled_at,
|
115
|
+
begin_to_remind: attrs.begin_to_remind,
|
116
|
+
autocompletable: attrs.autocompletable,
|
117
|
+
assignables_attributes: assignables_attributes,
|
118
|
+
callables_attributes: callables_attributes
|
119
|
+
}
|
120
|
+
},
|
121
|
+
success: function(response) {
|
122
|
+
var obj = Ext.JSON.decode(response.responseText);
|
123
|
+
self.set(obj.plan);
|
124
|
+
self.commit();
|
125
|
+
|
126
|
+
if(success) success.call(opts.scope || this);
|
127
|
+
}
|
128
|
+
});
|
129
|
+
Ext.Ajax.request(opts);
|
130
|
+
|
131
|
+
return plan;
|
132
|
+
},
|
133
|
+
|
134
|
+
statics: {
|
135
|
+
create: function(attrs, opts) {
|
136
|
+
var plan = Ext.create('TM.model.Plan', attrs);
|
137
|
+
|
138
|
+
opts = opts || {};
|
139
|
+
var success = opts.success;
|
140
|
+
|
141
|
+
var assignables_attributes = new Array();
|
142
|
+
Ext.Array.forEach(attrs.assignees, function(node, index, assignees) {
|
143
|
+
var record = Ext.getStore('TM.store.Assignees').getById(node.get('id'));
|
144
|
+
assignables_attributes.push({
|
145
|
+
assignee_id: record.get('id'),
|
146
|
+
assignee_type: record.get('class_name')
|
147
|
+
})
|
148
|
+
});
|
149
|
+
|
150
|
+
var callables_attributes = new Array();
|
151
|
+
|
152
|
+
Ext.apply(opts, {
|
153
|
+
url: '/task-manager/api/plans',
|
154
|
+
method: 'POST',
|
155
|
+
jsonData: {
|
156
|
+
plan: {
|
157
|
+
data: {
|
158
|
+
x: attrs.dataX,
|
159
|
+
y: attrs.dataY,
|
160
|
+
deadline_month: attrs.plan_type == 'quarterly' ? attrs.quarterly_month : (attrs.plan_type == 'yearly' ? attrs.month : null),
|
161
|
+
deadline_day: attrs.plan_type == 'weekly' ? attrs.weekly_day : (attrs.plan_type == 'daily' ? null : attrs.day),
|
162
|
+
deadline_hour: attrs.hour,
|
163
|
+
deadline_minute: attrs.minute
|
164
|
+
},
|
165
|
+
name: attrs.name,
|
166
|
+
plan_type: attrs.plan_type,
|
167
|
+
enabled_at: attrs.enabled_at,
|
168
|
+
begin_to_remind: attrs.begin_to_remind,
|
169
|
+
autocompletable: attrs.autocompletable,
|
170
|
+
assignables_attributes: assignables_attributes,
|
171
|
+
callables_attributes: callables_attributes
|
172
|
+
}
|
173
|
+
},
|
174
|
+
success: function(response) {
|
175
|
+
var obj = Ext.JSON.decode(response.responseText);
|
176
|
+
plan.set(obj.plan);
|
177
|
+
//plan.set('dataX', obj.plan.data.x);
|
178
|
+
plan.commit();
|
179
|
+
|
180
|
+
if(success) success.call(opts.scope || this);
|
181
|
+
}
|
182
|
+
});
|
183
|
+
Ext.Ajax.request(opts);
|
184
|
+
|
185
|
+
return plan;
|
186
|
+
}
|
187
|
+
},
|
188
|
+
|
189
|
+
destroy: function() {
|
190
|
+
this.callParent(arguments);
|
191
|
+
|
192
|
+
if(this.store) this.store.remove(this);
|
193
|
+
}
|
194
|
+
});
|
195
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Ext.define('TM.model.Task', {
|
2
|
+
extend: 'Ext.data.Model',
|
3
|
+
|
4
|
+
fields: [
|
5
|
+
{ name: 'id', type: 'int' },
|
6
|
+
{ name: 'name'},
|
7
|
+
{ name: 'task_type'},
|
8
|
+
{ name: 'data', type: 'auto' },
|
9
|
+
{ name: 'status' },
|
10
|
+
{ name: 'deadline', type: 'date'},
|
11
|
+
{ name: 'created_at', type: 'date' },
|
12
|
+
{ name: 'updated_at', type: 'date' }
|
13
|
+
],
|
14
|
+
|
15
|
+
proxy: {
|
16
|
+
type: 'rest',
|
17
|
+
url: '/task-manager/api/tasks',
|
18
|
+
reader: {
|
19
|
+
root: 'tasks',
|
20
|
+
totalProperty: 'total'
|
21
|
+
}
|
22
|
+
},
|
23
|
+
});
|
@@ -0,0 +1,53 @@
|
|
1
|
+
Ext.define('TM.store.Assignees', {
|
2
|
+
extend: 'Ext.data.Store',
|
3
|
+
|
4
|
+
autoLoad: true,
|
5
|
+
model: 'TM.model.Assignee',
|
6
|
+
|
7
|
+
toTreeStore: function() {
|
8
|
+
|
9
|
+
var self = this;
|
10
|
+
var store = {
|
11
|
+
root: {
|
12
|
+
expanded: true,
|
13
|
+
children: []
|
14
|
+
}
|
15
|
+
};
|
16
|
+
|
17
|
+
self.each(function(assignee) {
|
18
|
+
self.addChild(self.getPositionById(store.root,
|
19
|
+
assignee.get('parent_id')), assignee);
|
20
|
+
});
|
21
|
+
|
22
|
+
return store;
|
23
|
+
},
|
24
|
+
|
25
|
+
// @private
|
26
|
+
getPositionById: function(root, id) {
|
27
|
+
if (id == null || id == 0) return root;
|
28
|
+
if (root.id == id) return root;
|
29
|
+
|
30
|
+
var childrenLength = root.children ? root.children.length : 0;
|
31
|
+
for (var i = 0; i < childrenLength; i++) {
|
32
|
+
var result = this.getPositionById(root.children[i], id);
|
33
|
+
if (result != null) return result;
|
34
|
+
}
|
35
|
+
|
36
|
+
return null;
|
37
|
+
},
|
38
|
+
|
39
|
+
addChild: function(root, record) {
|
40
|
+
if (root.children == null) root.children = [];
|
41
|
+
|
42
|
+
root.children.push({
|
43
|
+
id: record.get('id'),
|
44
|
+
text: record.get('name'),
|
45
|
+
checked: false,
|
46
|
+
leaf: true
|
47
|
+
});
|
48
|
+
|
49
|
+
if (root.leaf != null) {
|
50
|
+
root.leaf == true ? root.leaf = false : null;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
});
|
@@ -0,0 +1,38 @@
|
|
1
|
+
Ext.define('TM.store.Days', {
|
2
|
+
extend: 'Ext.data.Store',
|
3
|
+
|
4
|
+
fields: ['text', 'value'],
|
5
|
+
data : [
|
6
|
+
{ "text": "1", 'value': '1' },
|
7
|
+
{ "text": "2", 'value': '2' },
|
8
|
+
{ "text": "3", 'value': '3' },
|
9
|
+
{ "text": "4", 'value': '4' },
|
10
|
+
{ "text": "5", 'value': '5' },
|
11
|
+
{ "text": "6", 'value': '6' },
|
12
|
+
{ "text": "7", 'value': '7' },
|
13
|
+
{ "text": "8", 'value': '8' },
|
14
|
+
{ "text": "9", 'value': '9' },
|
15
|
+
{ "text": "10", 'value': '10' },
|
16
|
+
{ "text": "11", 'value': '11' },
|
17
|
+
{ "text": "12", 'value': '12' },
|
18
|
+
{ "text": "13", 'value': '13' },
|
19
|
+
{ "text": "14", 'value': '14' },
|
20
|
+
{ "text": "15", 'value': '15' },
|
21
|
+
{ "text": "16", 'value': '16' },
|
22
|
+
{ "text": "17", 'value': '17' },
|
23
|
+
{ "text": "18", 'value': '18' },
|
24
|
+
{ "text": "19", 'value': '19' },
|
25
|
+
{ "text": "20", 'value': '20' },
|
26
|
+
{ "text": "21", 'value': '21' },
|
27
|
+
{ "text": "22", 'value': '22' },
|
28
|
+
{ "text": "23", 'value': '23' },
|
29
|
+
{ "text": "24", 'value': '24' },
|
30
|
+
{ "text": "25", 'value': '25' },
|
31
|
+
{ "text": "26", 'value': '26' },
|
32
|
+
{ "text": "27", 'value': '27' },
|
33
|
+
{ "text": "28", 'value': '28' },
|
34
|
+
{ "text": "29", 'value': '29' },
|
35
|
+
{ "text": "30", 'value': '30' },
|
36
|
+
{ "text": "31", 'value': '31' }
|
37
|
+
]
|
38
|
+
});
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Ext.define('TM.store.Hours',{
|
2
|
+
extend: 'Ext.data.Store',
|
3
|
+
|
4
|
+
fields: ['text', 'value'],
|
5
|
+
data : [
|
6
|
+
{ "text": "0时", 'value': '0' },
|
7
|
+
{ "text": "1时", 'value': '1' },
|
8
|
+
{ "text": "2时", 'value': '2' },
|
9
|
+
{ "text": "3时", 'value': '3' },
|
10
|
+
{ "text": "4时", 'value': '4' },
|
11
|
+
{ "text": "5时", 'value': '5' },
|
12
|
+
{ "text": "6时", 'value': '6' },
|
13
|
+
{ "text": "7时", 'value': '7' },
|
14
|
+
{ "text": "8时", 'value': '8' },
|
15
|
+
{ "text": "9时", 'value': '9' },
|
16
|
+
{ "text": "10时", 'value': '10' },
|
17
|
+
{ "text": "11时", 'value': '11' },
|
18
|
+
{ "text": "12时", 'value': '12' },
|
19
|
+
{ "text": "13时", 'value': '13' },
|
20
|
+
{ "text": "14时", 'value': '14' },
|
21
|
+
{ "text": "15时", 'value': '15' },
|
22
|
+
{ "text": "16时", 'value': '16' },
|
23
|
+
{ "text": "17时", 'value': '17' },
|
24
|
+
{ "text": "18时", 'value': '18' },
|
25
|
+
{ "text": "19时", 'value': '19' },
|
26
|
+
{ "text": "20时", 'value': '20' },
|
27
|
+
{ "text": "21时", 'value': '21' },
|
28
|
+
{ "text": "22时", 'value': '22' },
|
29
|
+
{ "text": "23时", 'value': '23' }
|
30
|
+
]
|
31
|
+
});
|