可扩展自动消息检测提醒系统
解决方案
-
通过任务队列实现自动化
-
通过对任务定制实现消息收发
-
通过API和GitHub实现扩展

前端 Vue.js
1. Index实现主页/登录
2. Register注册页
3. Manage用户任务管理
4. Log任务日志查看
import Vue from 'vue';
import Router from 'vue-router';
import Register from '@/components/Register';
import Index from '@/components/Index';
import Manage from '@/components/Manage';
import Log from '@/components/Log';
Vue.use(Router);
export default new Router({
routes: [
{
path: '/',
name: 'Index',
component: Index,
},
{
path: '/register',
name: 'Register',
component: Register,
},
{
path: '/manage',
name: 'Manage',
component: Manage,
},
{
path: '/log/:id',
name: 'Log',
component: Log,
},
],
});
文件结构
router 控制路由、页面跳转
模块化components
store存储了页面状态

Index
export default {
name: 'index',
components: {
Particles,
Navbar,
Panel,
FunctionsStatus,
},
data() {
return {
};
},
};

Register
mounted: function mounted() {...},
watch: {
username() {...},
email() {...},
code() {...},
password() {...},
},
methods: {
ok() {...},
visiableChange(visiable) {...},
register() {...},
registerStatus() {...},
usernameTest(only) {...},
passwordTest() {...},
emailTest(only) {...},
codeTest(only) {...},
},
computed: {
usernameFeedback() {...},
usernameState() {...},
passwordFeedback() {...},
passwordState() {...},
emailFeedback() {...},
emailState() {...},
codeFeedback() {...},
codeState() {...},
},

Manage

methods: {
visiableChange(visiable) {...},
generateParams(ajaxURL) {...},
initChangeForm(id) {...},
initForm() {...},
submitChange(e) {...},
submitCreate(e) {...},
taskDelete(id) {...},
getFunctions() {...},
getFuncForm(id) {...},
updateTableState() {...},
getTask() {...},
watch: {
createFunc: function createFunc(newFuncID) {...},
items: function items() {...},
},
mounted: function mounted() {...},Log
getLog() {
Axios({
method: 'get',
url: `/api/core/task/log/${this.$route.params.id}/`,
})
.then((response) => {
if (response.data.status === 213) {
this.logs = response.data.data;
this.$set(this, 'toastr', {
message: response.data.message,
title: 'Loaded',
type: 'success',
});
} else {
this.$set(this, 'toastr', {
message: response.data.message,
title: 'error',
type: 'warning',
});
}
this.$set(this, 'visiable', true);
})
.catch((response) => {
this.$set(this, 'toastr', {
message: response.data,
title: 'Server error, please contact server manager',
type: 'error',
});
this.$set(this, 'visiable', true);
});
},
后端 Django
1. RESTfulAPI
2. 核心框架send_core
3. 扩展APP
from django.conf.urls import url
from send_core import views
urlpatterns = [
url(r'^$', views.index),
url(r'^get/functions/$', views.get_functions),
url(r'^user/whoami/$', views.whoami),
url(r'^user/login/$', views.login),
url(r'^user/logout/$', views.logout),
url(r'^user/register/$', views.register),
url(r'^get/status/(?P<target>\w+)/$', views.status),
url(r'^get/function/form/(?P<target>\d+)/$', views.get_function_form),
url(r'^user/username/valid/$', views.username_valid),
url(r'^user/email/valid/$', views.email_valid),
url(r'^user/code/valid/$', views.code_valid),
url(r'^user/task/$', views.task),
url(r'^task/create/$', views.task_create),
url(r'^task/detail/(?P<target>\d+)/$', views.task_detail),
url(r'^task/change/$', views.task_change),
url(r'^task/delete/(?P<target>\d+)/$', views.task_delete),
url(r'^task/log/(?P<target>\d+)/$', views.task_log),
]eg: 用户修改任务参数(API)
def task_change(request):
response = {
'status': -1,
'message': 'error',
}
if request.user.is_authenticated():
raw_data = json.loads(request.body.decode())
if raw_data['taskID'] <= 0: # check it is cause by change.
response['status'] = 452
response['message'] = 'taskID error'
else:
tasks = Task.objects.filter(id=raw_data['taskID'])
if len(tasks) == 1:
task = tasks[0]
if task.person == request.user: # check belongs
task.params = json.dumps({'input': raw_data['input']}, ensure_ascii=False)
task.comment = raw_data['input'][-1]['value']
task.check = 0
task.status = '重新创建'
task.save()
response['status'] = 211
response['message'] = 'change success, task id is %d' % raw_data['taskID']
else:
response['status'] = 451
response['message'] = 'This task is not belongs to you'
return HttpResponse(json.dumps(response))eg: Task表结构(django.db.models)
class Task(models.Model):
person = models.ForeignKey(User, related_name='person_task', db_index=True)
function = models.ForeignKey(Function, related_name='function_task', db_index=True)
comment = models.CharField(max_length=128, default='')
status = models.CharField(max_length=128, default='')
success = models.IntegerField(default=0)
failed = models.IntegerField(default=0)
last_exec = models.DateTimeField(blank=True)
next_exec = models.DateTimeField(blank=True)
params = models.CharField(max_length=2048, default='{}') # json.dumps
check = models.IntegerField(default=0)
def __str__(self):
return '[%d]%s start %s, %s, next is %s' % (self.id, self.person.username,
self.function.name, self.status, self.next_exec.strftime('%Y-%m-%d %H:%M:%S'))
class Meta:
ordering = ['id', 'person', 'function'] 任务调度逻辑
1. Celery发现任务
2. task.py包含任务
3. 任务结束后发出消息
app = Celery('send_core', backend='amqp://guest@127.0.0.1//', broker='amqp://guest@127.0.0.1//')
app.conf.update(
CELERY_ACCEPT_CONTENT = ['application/json'],
CELERY_TASK_SERIALIZER = 'json',
CELERY_RESULT_SERIALIZER = 'json',
CELERY_TIMEZONE = 'Asia/Chongqing',
)
app.config_from_object('django.conf:settings')
app.autodiscover_tasks()@periodic_task(run_every=crontab(minute='*/1'), name='send_core_check')
def send_core_check():
print('send core is running')@shared_task(default_retry_delay=5, max_retries=3)
def check_one(taskid):
try:
new_message = func.check_one(taskid)
if len(new_message) > 0:
task = Task.objects.filter(id=taskid)[0]
title = 'new uestc grade of %s' % task.comment
plain = json.dumps(new_message, ensure_ascii=False, indent=4)
async_select_and_send.delay(task.person.email, title, plain) // send
func.plus()
except Exception as e:
return check_one.retry(taskid)demo APP
1. __init__.py初始化数据
2. task.py定义任务和规则
3. func.py包含更细节的方法
4. models.py定义了数据表

谢谢
中期答辩
By lc
中期答辩
- 664