diff --git a/dvadmin-backend/application/settings.py b/dvadmin-backend/application/settings.py
index 1b1ba17..60e33c0 100644
--- a/dvadmin-backend/application/settings.py
+++ b/dvadmin-backend/application/settings.py
@@ -45,10 +45,12 @@ INSTALLED_APPS = [
     'rest_framework',
     'corsheaders',
     'captcha',
+    'djcelery',
     # 自定义app
     'apps.vadmin.permission',
     'apps.vadmin.op_drf',
     'apps.vadmin.system',
+    'apps.vadmin.celery',
 ]
 
 MIDDLEWARE = [
diff --git a/dvadmin-backend/apps/vadmin/celery/__init__.py b/dvadmin-backend/apps/vadmin/celery/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/dvadmin-backend/apps/vadmin/celery/admin.py b/dvadmin-backend/apps/vadmin/celery/admin.py
new file mode 100644
index 0000000..694323f
--- /dev/null
+++ b/dvadmin-backend/apps/vadmin/celery/admin.py
@@ -0,0 +1 @@
+from django.contrib import admin
diff --git a/dvadmin-backend/apps/vadmin/celery/apps.py b/dvadmin-backend/apps/vadmin/celery/apps.py
new file mode 100644
index 0000000..efafaf1
--- /dev/null
+++ b/dvadmin-backend/apps/vadmin/celery/apps.py
@@ -0,0 +1,7 @@
+from django.apps import AppConfig
+
+
+class DpCmdbConfig(AppConfig):
+    name = 'vadmin.celery'
+
+
diff --git a/dvadmin-backend/apps/vadmin/celery/filters.py b/dvadmin-backend/apps/vadmin/celery/filters.py
new file mode 100644
index 0000000..8d5b806
--- /dev/null
+++ b/dvadmin-backend/apps/vadmin/celery/filters.py
@@ -0,0 +1,21 @@
+import django_filters
+from djcelery.models import IntervalSchedule, CrontabSchedule, PeriodicTask
+
+
+class IntervalScheduleFilter(django_filters.rest_framework.FilterSet):
+    class Meta:
+        model = IntervalSchedule
+        fields = '__all__'
+
+
+class CrontabScheduleFilter(django_filters.rest_framework.FilterSet):
+    class Meta:
+        model = CrontabSchedule
+        fields = '__all__'
+
+
+class PeriodicTaskFilter(django_filters.rest_framework.FilterSet):
+    class Meta:
+        model = PeriodicTask
+        fields = '__all__'
+
diff --git a/dvadmin-backend/apps/vadmin/celery/models/__init__.py b/dvadmin-backend/apps/vadmin/celery/models/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/dvadmin-backend/apps/vadmin/celery/serializers.py b/dvadmin-backend/apps/vadmin/celery/serializers.py
new file mode 100644
index 0000000..e029cb4
--- /dev/null
+++ b/dvadmin-backend/apps/vadmin/celery/serializers.py
@@ -0,0 +1,41 @@
+from djcelery.models import IntervalSchedule, CrontabSchedule, PeriodicTask
+from rest_framework import serializers
+
+from ..op_drf.serializers import CustomModelSerializer
+from ..utils.exceptions import APIException
+
+
+class IntervalScheduleSerializer(CustomModelSerializer):
+    class Meta:
+        model = IntervalSchedule
+        fields = '__all__'
+
+
+class CrontabScheduleSerializer(CustomModelSerializer):
+
+    def save(self, **kwargs):
+        queryset = CrontabSchedule.objects.filter(**self.validated_data)
+        if queryset.count() and (
+                queryset.count() == 1 and self.initial_data.get('id', None) not in queryset.values_list('id',
+                                                                                                        flat=True)):
+            raise APIException(message='值已存在!!!')
+        super().save(**kwargs)
+
+    class Meta:
+        model = CrontabSchedule
+        fields = '__all__'
+
+
+class PeriodicTaskSerializer(CustomModelSerializer):
+    interval_list = serializers.SerializerMethodField(read_only=True)
+    crontab_list = serializers.SerializerMethodField(read_only=True)
+
+    def get_interval_list(self, obj):
+        return IntervalScheduleSerializer(obj.interval).data if obj.interval else {}
+
+    def get_crontab_list(self, obj):
+        return CrontabScheduleSerializer(obj.crontab).data if obj.crontab else {}
+
+    class Meta:
+        model = PeriodicTask
+        fields = '__all__'
diff --git a/dvadmin-backend/apps/vadmin/celery/tasks.py b/dvadmin-backend/apps/vadmin/celery/tasks.py
new file mode 100644
index 0000000..e69de29
diff --git a/dvadmin-backend/apps/vadmin/celery/tests.py b/dvadmin-backend/apps/vadmin/celery/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/dvadmin-backend/apps/vadmin/celery/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/dvadmin-backend/apps/vadmin/celery/urls.py b/dvadmin-backend/apps/vadmin/celery/urls.py
new file mode 100644
index 0000000..40d523a
--- /dev/null
+++ b/dvadmin-backend/apps/vadmin/celery/urls.py
@@ -0,0 +1,20 @@
+from django.conf.urls import url
+from rest_framework.routers import DefaultRouter
+from rest_framework.urlpatterns import format_suffix_patterns
+
+from apps.vadmin.celery.views import IntervalScheduleModelViewSet, CrontabScheduleModelViewSet, PeriodicTaskModelViewSet, TasksAsChoices, \
+    OperateCeleryTask
+
+router = DefaultRouter()
+# 调度间隔
+router.register(r'intervalschedule', IntervalScheduleModelViewSet)
+router.register(r'crontabschedule', CrontabScheduleModelViewSet)
+router.register(r'periodictask', PeriodicTaskModelViewSet)
+
+urlpatterns = format_suffix_patterns([
+    # 获取所有 tasks 名称
+    url(r'^tasks_as_choices/', TasksAsChoices.as_view()),
+    url(r'^operate_celery/', OperateCeleryTask.as_view()),
+])
+
+urlpatterns += router.urls
diff --git a/dvadmin-backend/apps/vadmin/celery/views.py b/dvadmin-backend/apps/vadmin/celery/views.py
new file mode 100644
index 0000000..df26138
--- /dev/null
+++ b/dvadmin-backend/apps/vadmin/celery/views.py
@@ -0,0 +1,101 @@
+from djcelery.admin import TaskSelectWidget
+from djcelery.models import IntervalSchedule, CrontabSchedule, PeriodicTask
+from rest_framework.views import APIView
+
+from ..celery.filters import IntervalScheduleFilter, CrontabScheduleFilter, PeriodicTaskFilter
+from ..celery.serializers import IntervalScheduleSerializer, CrontabScheduleSerializer, PeriodicTaskSerializer
+from ..op_drf.views import CustomAPIView
+from ..op_drf.viewsets import CustomModelViewSet
+from ..system.models import DictData
+from ..system.serializers import DictDataSerializer
+from ..utils.response import SuccessResponse
+
+
+class IntervalScheduleModelViewSet(CustomModelViewSet):
+    """
+    IntervalSchedule 调度间隔模型
+    every 次数
+    period 时间(天,小时,分钟,秒.毫秒)
+    """
+    queryset = IntervalSchedule.objects.all()
+    serializer_class = IntervalScheduleSerializer
+    create_serializer_class = IntervalScheduleSerializer
+    update_serializer_class = IntervalScheduleSerializer
+    filter_class = IntervalScheduleFilter
+    search_fields = ('every', 'period')
+    ordering = 'every'  # 默认排序
+
+
+class CrontabScheduleModelViewSet(CustomModelViewSet):
+    """
+    CrontabSchedule crontab调度模型
+    minute 分钟
+    hour 小时
+    day_of_week 每周的周几
+    day_of_month 每月的某一天
+    month_of_year 每年的某一个月
+
+    """
+    queryset = CrontabSchedule.objects.all()
+    serializer_class = CrontabScheduleSerializer
+    filter_class = CrontabScheduleFilter
+    search_fields = ('minute', 'hour')
+    ordering = 'minute'  # 默认排序
+
+
+class PeriodicTaskModelViewSet(CustomModelViewSet):
+    """
+    PeriodicTask celery 任务数据模型
+    name 名称
+    task celery任务名称
+    interval 频率
+    crontab 任务编排
+    args 形式参数
+    kwargs 位置参数
+    queue 队列名称
+    exchange 交换
+    routing_key 路由密钥
+    expires 过期时间
+    enabled 是否开启
+
+    """
+    queryset = PeriodicTask.objects.all()
+    serializer_class = PeriodicTaskSerializer
+    filter_class = PeriodicTaskFilter
+    search_fields = ('name', 'task', 'date_changed')
+    ordering = 'date_changed'  # 默认排序
+
+
+class TasksAsChoices(APIView):
+    def get(self, request):
+        """
+        获取所有 tasks 名称
+        :param request:
+        :return:
+        """
+        lis = []
+
+        def get_data(datas):
+            for item in datas:
+                if isinstance(item, (str, int)) and item:
+                    lis.append(item)
+                else:
+                    get_data(item)
+
+        get_data(TaskSelectWidget().tasks_as_choices())
+        return SuccessResponse(list(set(lis)))
+
+
+class OperateCeleryTask(CustomAPIView):
+    def post(self, request):
+        req_data = request.data
+        task = req_data.get('celery_name', '')
+        data = {
+            'task': ''
+        }
+        test = f"""
+from {'.'.join(task.split('.')[:-1])} import {task.split('.')[-1]}
+task = {task.split('.')[-1]}.delay()
+        """
+        exec(test, data)
+        return SuccessResponse({'task_id': data.get('task').id})
diff --git a/dvadmin-backend/apps/vadmin/op_drf/logging/view_logger.py b/dvadmin-backend/apps/vadmin/op_drf/logging/view_logger.py
index f60f3ee..3e03558 100644
--- a/dvadmin-backend/apps/vadmin/op_drf/logging/view_logger.py
+++ b/dvadmin-backend/apps/vadmin/op_drf/logging/view_logger.py
@@ -24,7 +24,7 @@ class ViewLogger(object):
                                                                                    'model'):
             self.model: Model = self.view.get_serializer().Meta.model
         if self.model:
-            request.session['model_name'] = getattr(self.model, '_meta').verbose_name
+            request.session['model_name'] = str(getattr(self.model, '_meta').verbose_name)
 
     def handle(self, request: Request, *args, **kwargs):
         pass
@@ -38,6 +38,7 @@ class ViewLogger(object):
         self.request.session['request_msg'] = msg
         return logger
 
+
 class APIViewLogger(ViewLogger):
     """
     (1)仅在op_drf.views.CustomAPIView的子类中生效
diff --git a/dvadmin-backend/apps/vadmin/urls.py b/dvadmin-backend/apps/vadmin/urls.py
index 341e6fb..093e65d 100644
--- a/dvadmin-backend/apps/vadmin/urls.py
+++ b/dvadmin-backend/apps/vadmin/urls.py
@@ -53,5 +53,6 @@ urlpatterns = [
     re_path('captcha/', include('captcha.urls')),  # 图片验证码 路由
     re_path(r'^permission/', include('apps.vadmin.permission.urls')),
     re_path(r'^system/', include('apps.vadmin.system.urls')),
+    re_path(r'^celery/', include('apps.vadmin.celery.urls')),
 
 ]
diff --git a/dvadmin-backend/apps/vadmin/utils/exceptions.py b/dvadmin-backend/apps/vadmin/utils/exceptions.py
index b07262b..cbd065e 100644
--- a/dvadmin-backend/apps/vadmin/utils/exceptions.py
+++ b/dvadmin-backend/apps/vadmin/utils/exceptions.py
@@ -1,7 +1,7 @@
 import logging
 import traceback
 
-from rest_framework import serializers, exceptions
+from rest_framework import exceptions
 from rest_framework.views import set_rollback
 
 from .request_util import get_verbose_name
@@ -18,9 +18,9 @@ class APIException(Exception):
     """
 
     def __init__(self, code=201, message='API异常', args=('API异常',)):
-        args = args
-        code = code
-        message = message
+        self.args = args
+        self.code = code
+        self.message = message
 
     def __str__(self):
         return self.message
@@ -36,8 +36,8 @@ class FrameworkException(Exception):
     """
 
     def __init__(self, message='框架异常', *args: object, **kwargs: object) -> None:
-        super().__init__(*args, **kwargs)
-        message = message
+        super().__init__(*args, )
+        self.message = message
 
     def __str__(self) -> str:
         return f"{self.message}"
@@ -66,7 +66,7 @@ def op_exception_handler(ex, context):
     msg = ''
     code = '201'
     request = context.get('request')
-    request.session['model_name'] = get_verbose_name(view=context.get('view'))
+    request.session['model_name'] = str(get_verbose_name(view=context.get('view')))
 
     if isinstance(ex, AuthenticationFailed):
         code = 401
@@ -80,4 +80,4 @@ def op_exception_handler(ex, context):
     elif isinstance(ex, Exception):
         logger.error(traceback.format_exc())
         msg = str(ex)
-    return ErrorResponse(msg=msg,code=code)
+    return ErrorResponse(msg=msg, code=code)
diff --git a/dvadmin-backend/requirements.txt b/dvadmin-backend/requirements.txt
index 3c2399d..b99e992 100644
--- a/dvadmin-backend/requirements.txt
+++ b/dvadmin-backend/requirements.txt
@@ -1,6 +1,7 @@
 asgiref==3.3.1
 Django==2.2.16
 django-cors-headers==3.7.0
+django-celery==3.2.2
 django-filter==2.4.0
 django-ranged-response==0.2.0
 django-redis==4.12.1
diff --git a/dvadmin-doc/docs/document/hjbs.md b/dvadmin-doc/docs/document/hjbs.md
index 52653ef..5e81cba 100644
--- a/dvadmin-doc/docs/document/hjbs.md
+++ b/dvadmin-doc/docs/document/hjbs.md
@@ -1 +1,98 @@
 # 环境部署
+## 1.前端搭建环境
+
+### 1.1 安装node
+
+## 1. 后端搭建环境
+
+### 1.1 安装Python3.8
+
+### 1.2 安装Reids
+        sudo apt-get install -y redis-server
+
+### 1.3 安装nginx
+        sudo apt-get install -y nginx
+
+### 1.1 安装其它软件
+        sudo apt-get install -y python3-venv pcre pcre-devel pcre-static zlib* gcc openssl openssl-devel libffi-devel 
+
+## 2. 创建虚拟环境
+### 2.1 进入项目目录 cd gh-baohua-backend
+        在项目根目录中,复制./conf/env.example.py文件为一份新的到./conf文件夹下,并重命名为env.py,在env.py中配置数据库信息。
+
+### 2.2 激活虚拟环境
+
+#### 2.2.1 python(python3) -m venv xxxx-venv, (xxxx根据情况定义)
+
+#### 2.2.2 \xxxx-venv\Scripts\activate (window OS)
+
+#### 2.2.3 sudo chmod -R 777 xxxx-venv/* (Linux OS)
+#### 2.2.4 source ./gh-baohua-venv/bin/activate (Linux OS)
+
+## 3. 升级pip
+
+	sudo python(python3) -m pip install --upgrade pip
+
+## 4. 安装依赖环境
+
+	pip install -r requirements.txt
+
+## 5. 执行迁移命令:
+	python manage.py makemigrations
+	python manage.py migrate
+
+## 6. 初始化数据
+	python manage.py init
+
+## 7. 启动项目
+	python manage.py runserver 8888
+
+## 8. 初始账号:admin  密码:123456
+
+## 9. 搭建正式环境,完成上述步骤1-6
+
+### 9.1 配置uwsgi.ini(主要配置项)
+
+[uwsgi]
+
+chdir           = /mnt/dvadmin-backend
+wsgi-file       = /mnt/dvadmin-backend/application/wsgi.py
+home            = /mnt/dvadmin-backend/leo-baohua-venv
+pidfile = /mnt/dvadmin-backend/uwsgi.pid
+daemonize = /mnt/dvadmin-backend/uwsgi.log
+master          = true
+processes       = 8
+socket          = 0.0.0.0:7777
+module          = application.wsgi:application
+vacuum          = true
+
+### 9.2 Nginx 配置
+
+#### 9.2.1 配置uwsgi
+        server {
+                listen 7077;
+                server_name 192.168.xx.xxx;
+    
+                location / {
+                        include uwsgi_params;
+                        uwsgi_pass 127.0.0.1:7777;
+                }
+        }
+
+#### 9.2.2 配置前端
+        server {
+                listen 7078;
+                server_name 192.168.xx.xxx;
+    
+                root /mnt/dvadmin-ui/dist;
+    
+                index index.html index.htm index.nginx-debian.html;
+    
+                location / {
+                        try_files $uri $uri/ /index.html;
+                }
+        }
+
+#### 9.2.3 配置前端接口-env.production
+VUE_APP_BASE_API = 'http://192.168.xx.xxx:7077'
+
diff --git a/dvadmin-ui/package.json b/dvadmin-ui/package.json
index 7a917c8..2637669 100755
--- a/dvadmin-ui/package.json
+++ b/dvadmin-ui/package.json
@@ -49,6 +49,7 @@
     "js-beautify": "1.13.0",
     "js-cookie": "2.2.1",
     "jsencrypt": "3.0.0-rc.1",
+    "moment": "^2.29.1",
     "nprogress": "0.2.0",
     "quill": "1.3.7",
     "screenfull": "5.0.2",
diff --git a/dvadmin-ui/src/api/vadmin/monitor/celery.js b/dvadmin-ui/src/api/vadmin/monitor/celery.js
new file mode 100644
index 0000000..d21c8a1
--- /dev/null
+++ b/dvadmin-ui/src/api/vadmin/monitor/celery.js
@@ -0,0 +1,146 @@
+import request from '@/utils/request'
+/**
+ * 封装celery任务信息接口请求
+ */
+// 获取
+export const sync_data_prefix = '/admin/celery';
+
+// 获取
+export function getIntervalschedulea(id) {
+  return request({
+    url: `${sync_data_prefix}/intervalschedule/${id}/`,
+    method: 'get'
+  });
+}
+
+// 获取
+export function listIntervalschedule(params) {
+  return request({
+    url: `${sync_data_prefix}/intervalschedule/`,
+    method: 'get',
+    params
+  });
+}
+
+// 更新
+export function updateIntervalschedule(data) {
+  return request({
+    url: `${sync_data_prefix}/intervalschedule/${data.id}/`,
+    method: 'put',
+    data
+  });
+}
+// 新增
+export function createIntervalschedule(data) {
+  return request({
+    url: `${sync_data_prefix}/intervalschedule/`,
+    method: 'post',
+    data
+  });
+}
+// 删除
+export function deleteIntervalschedule(id) {
+  return request({
+    url: `${sync_data_prefix}/intervalschedule/${id}/`,
+    method: 'delete'
+  });
+}
+
+// 获取
+export function getCrontabSchedule(id) {
+  return request({
+    url: `${sync_data_prefix}/crontabschedule/${id}/`,
+    method: 'get'
+  });
+}
+
+// 获取
+export function listCrontabSchedule(params) {
+  return request({
+    url: `${sync_data_prefix}/crontabschedule/`,
+    method: 'get',
+    params
+  });
+}
+
+// 更新
+export function updateCrontabSchedule(data) {
+  return request({
+    url: `${sync_data_prefix}/crontabschedule/${data.id}/`,
+    method: 'put',
+    data
+  });
+}
+// 新增
+export function createCrontabSchedule(data) {
+  return request({
+    url: `${sync_data_prefix}/crontabschedule/`,
+    method: 'post',
+    data
+  });
+}
+// 删除
+export function deleteCrontabSchedule(id) {
+  return request({
+    url: `${sync_data_prefix}/crontabschedule/${id}/`,
+    method: 'delete'
+  });
+}
+
+// 获取
+export function getPeriodicTask(id) {
+  return request({
+    url: `${sync_data_prefix}/periodictask/${id}/`,
+    method: 'get'
+  });
+}
+
+// 获取
+export function listPeriodicTask(params) {
+  return request({
+    url: `${sync_data_prefix}/periodictask/`,
+    method: 'get',
+    params
+  });
+}
+// 获取所有 tasks 名称
+export function TasksAsChoices(params) {
+  return request({
+    url: `${sync_data_prefix}/tasks_as_choices/`,
+    method: 'get',
+    params
+  });
+}
+
+// 更新
+export function updatePeriodicTask(data) {
+  return request({
+    url: `${sync_data_prefix}/periodictask/${data.id}/`,
+    method: 'put',
+    data
+  });
+}
+// 新增
+export function createPeriodicTask(data) {
+  return request({
+    url: `${sync_data_prefix}/periodictask/`,
+    method: 'post',
+    data
+  });
+}
+// 删除
+export function deletePeriodicTask(id) {
+  return request({
+    url: `${sync_data_prefix}/periodictask/${id}/`,
+    method: 'delete'
+  });
+}
+
+// 获取
+export function operatesyncdata(data) {
+  return request({
+    url: `${sync_data_prefix}/operate_celery/`,
+    method: 'post',
+    data
+  });
+}
diff --git a/dvadmin-ui/src/assets/icons/svg/icon-excel.svg b/dvadmin-ui/src/assets/icons/svg/icon-excel.svg
new file mode 100644
index 0000000..bb00722
--- /dev/null
+++ b/dvadmin-ui/src/assets/icons/svg/icon-excel.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1576580909902" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1356" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M625.664 132.608v67.072h309.76v43.008h-309.76v69.632h309.76v43.008h-309.76v68.608h309.76v43.008h-309.76v68.608h309.76v43.008h-309.76v68.608h309.76v43.008h-309.76v68.096h309.76v43.008h-309.76v89.088H1024v-757.76H625.664zM0 914.944L577.024 1024V0L0 109.056v805.888z" p-id="1357"></path><path d="M229.376 660.48h-89.6l118.272-187.904-112.64-180.736h92.16l65.536 119.808 67.584-119.808h89.088l-112.64 177.664L466.944 660.48H373.248l-70.144-125.44z" p-id="1358"></path></svg>
\ No newline at end of file
diff --git a/dvadmin-ui/src/assets/icons/svg/icon-filter.svg b/dvadmin-ui/src/assets/icons/svg/icon-filter.svg
new file mode 100644
index 0000000..869117a
--- /dev/null
+++ b/dvadmin-ui/src/assets/icons/svg/icon-filter.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1592549265947" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1995" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M595.716 972.68c-7.013 0-13.911-2.279-19.616-6.788l-178.877-142.27c-7.47-5.929-11.803-15.052-11.803-24.63v-301.706c0-1.023-0.458-1.938-1.141-2.619l-283.803-283.915c-1.14-1.14-2.222-2.341-3.137-3.591-16.023-16.822-24.521-38.031-24.521-60.446 0-47.612 38.775-86.387 86.33-86.387h703.654c47.558 0 86.331 38.775 86.331 86.387 0 22.183-8.434 43.284-23.718 59.362-0.57 0.801-1.765 2.222-2.566 2.907l-294.576 294.691c-0.682 0.686-1.14 1.657-1.14 2.684v434.962c0 12.090-6.899 23.041-17.846 28.282-4.336 2.052-9.010 3.079-13.573 3.079v0zM448.259 783.823l116.038 92.266v-369.791c0-17.846 6.899-34.494 19.386-47.098l293.664-293.664c0.912-1.085 1.77-1.997 2.684-2.967 3.877-4.109 6.211-9.863 6.211-15.853 0-12.943-10.606-23.49-23.491-23.49h-703.596c-12.941 0-23.491 10.606-23.491 23.49 0 6.047 2.341 11.865 6.557 16.196 1.537 1.597 2.909 3.308 4.22 4.903l282.318 282.373c12.372 12.372 19.504 29.535 19.504 47.098v286.539zM448.259 783.823z" p-id="1996"></path></svg>
\ No newline at end of file
diff --git a/dvadmin-ui/src/components/CommonIcon/index.vue b/dvadmin-ui/src/components/CommonIcon/index.vue
new file mode 100644
index 0000000..2526060
--- /dev/null
+++ b/dvadmin-ui/src/components/CommonIcon/index.vue
@@ -0,0 +1,114 @@
+<!--
+@description: 封装组件, 通用图标组件(已注册全局组件)
+用法:<common-icon value="el:el-icon-delete-solid"/>
+用法:<common-icon value="svg:icon-folder"/>
+-->
+<template>
+  <!--<svg v-if="iconType && iconType.toLocaleLowerCase() === 'svg'" :class="commonClass" aria-hidden="true">
+    <use :xlink:href="commonName"/>
+  </svg>-->
+  <span>
+    <slot name="prepend"/>
+    <svg v-if="iconType && iconType.toLocaleLowerCase() === 'svg'" :class="commonClass" aria-hidden="true">
+      <use :xlink:href="commonName"/>
+    </svg>
+    <i v-if="iconType && iconType.toLocaleLowerCase() === 'el'" :class="commonClass"/>
+    <span v-if="showTitle">{{ iconTitle }}</span>
+    <slot name="append"/>
+  </span>
+</template>
+
+<script>
+export default {
+  name: 'CommonIcon',
+  props: {
+    value: {
+      type: String,
+      default: ''
+    },
+    iconTitle: {
+      type: String,
+      default: ''
+    },
+    iconClass: {
+      type: String,
+      required: false,
+      default: ''
+    },
+    showTitle: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data() {
+    return {
+      iconType: '',
+      iconName: '',
+      commonName: '',
+      commonClass: ''
+    };
+  },
+  computed: {
+  },
+  watch: {
+    value(val) {
+      this.change(val);
+    }
+  },
+  created() {
+  },
+  mounted() {
+    this.change(this.value);
+  },
+  methods: {
+    change(val) {
+      const arr = val.split(':');
+      if (arr.length >= 2) {
+        this.iconType = arr[0];
+        this.iconName = arr[1];
+      } else {
+        this.iconType = '';
+        this.iconName = '';
+      }
+      this.commonName = this.getCommonName();
+      this.commonClass = this.getCommonClass();
+    },
+    getCommonName() {
+      if (this.iconType && this.iconType.toLocaleLowerCase() === 'svg') {
+        return `#icon-${this.iconName}`;
+      }
+      if (this.iconType && this.iconType.toLocaleLowerCase() === 'el') {
+        return `${this.iconName}`;
+      }
+      return '';
+    },
+    getCommonClass() {
+      if (this.iconType && this.iconType.toLocaleLowerCase() === 'svg') {
+        if (this.className) {
+          return 'svg-icon ' + this.className;
+        } else {
+          return 'svg-icon';
+        }
+      }
+      if (this.iconType && this.iconType.toLocaleLowerCase() === 'el') {
+        if (this.className) {
+          return this.iconName + ' ' + this.className;
+        } else {
+          return this.iconName;
+        }
+      }
+      return '';
+    }
+  }
+};
+</script>
+
+<style scoped>
+.svg-icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+</style>
diff --git a/dvadmin-ui/src/components/CommonStaticTable/index.vue b/dvadmin-ui/src/components/CommonStaticTable/index.vue
new file mode 100644
index 0000000..fe92660
--- /dev/null
+++ b/dvadmin-ui/src/components/CommonStaticTable/index.vue
@@ -0,0 +1,465 @@
+<!--
+@description: 封装组件
+-->
+<template>
+  <div style="padding-left: 10px;">
+    <el-row v-if="topLayout" style="margin-bottom: 20px">
+      <el-col v-if="topLayoutLeft" :span="18">
+        <div class="grid-content bg-purple">
+          <el-input
+            v-model="searchForm.search"
+            :disabled="tableLoading"
+            :size="$ELEMENT.size"
+            :placeholder="filterPlaceholder"
+            clearable
+            style="width: 200px;"
+            @keyup.enter.native="handleSearchFormSubmit"/>
+          <el-button
+            :size="$ELEMENT.size"
+            type="primary"
+            title="过滤"
+            @click="handleSearchFormSubmit">
+            <common-icon value="svg:icon-filter"/>
+          </el-button>
+          <el-button
+            v-show="isFilter"
+            :size="$ELEMENT.size"
+            type="info"
+            title="取消过滤"
+            style="margin-left: 0;"
+            @click="handleCancelFilter">
+            <common-icon value="svg:icon-unfilter"/>
+          </el-button>
+          <slot name="button"/>
+        </div>
+      </el-col>
+      <el-col v-if="topLayoutRight" :span="6">
+        <div class="grid-content bg-purple-light" style="text-align: right">
+          <slot name="tools"/>
+          <el-button
+            :size="$ELEMENT.size"
+            name="refresh"
+            type="info"
+            title="导出数据"
+            @click="handleExportTableData">
+            <svg-icon icon-class="icon-excel" style="font-size: 1em"/>
+          </el-button>
+          <el-popover
+            placement="bottom"
+            width="200"
+            trigger="click">
+            <div style="width: 50px;">
+              <el-checkbox-group v-model="showFields">
+                <el-checkbox
+                  v-for="(field, index) in fields"
+                  :key="index"
+                  :label="field"
+                  :checked="field.show"
+                  style="width: 100%"
+                  @change="handleSelectField($event, field)">{{ field.label }}</el-checkbox>
+              </el-checkbox-group>
+            </div>
+            <el-button
+              slot="reference"
+              :size="$ELEMENT.size"
+              name="refresh"
+              type="info"
+              icon="el-icon-s-fold"
+              title="设置显示的字段"/>
+          </el-popover>
+        </div>
+      </el-col>
+    </el-row>
+    <el-table
+      v-loading="tableLoading"
+      ref="table"
+      :data="filterData"
+      :span-method="spanMethod"
+      :max-height="maxHeight"
+      :row-key="getRowKeys"
+      :stripe="stripe"
+      :fit="fit"
+      :border="border"
+      :empty-text="emptyText"
+      :highlight-current-row="highlightCurrentRow"
+      :show-overflow-tooltip="showOverflowTooltip"
+      @cell-click="handleCellClick"
+      @cell-dblclick="handleCellDbClick"
+      @header-click="handleHeaderClick"
+      @row-click="handleRowClick"
+      @row-dblclick="handleRowDblClick"
+      @selection-change="handleSelectionChange">
+      <el-table-column
+        v-if="selection"
+        :reserve-selection="true"
+        type="selection"
+        width="50"/>
+      <template v-for="field in fields">
+        <el-table-column
+          v-if="field.show"
+          :key="field.prop"
+          :prop="field.prop"
+          :label="field.label"
+          :sortable="field.sortable"
+          :width="field.width || ''"
+          show-overflow-tooltip>
+          <template slot-scope="scope">
+            <slot :name="field.prop" :values="scope.row" :prop="field.prop" :field="field">
+              <span v-html="formatColumnData(scope.row, field)"/>
+            </slot>
+          </template>
+        </el-table-column>
+      </template>
+      <slot name="column"/>
+    </el-table>
+    <el-row>
+      <el-col :span="6" style="margin-top: 20px">
+        <span>已选择:<span style="color: #ff00ff;font-weight: bold;">{{ multipleSelection.length }}</span>条</span>
+        <el-button
+          v-show="multipleSelection.length"
+          type="info"
+          size="mini"
+          title="清空多选"
+          @click="clearMultipleSelection">清空</el-button>
+      </el-col>
+      <el-col :span="18" style="margin-top: 20px; text-align: right">
+        <span>总计:<span style="color: #ff00ff;font-weight: bold;">{{ filterData.length }}</span>条</span>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+<script>
+  import moment from 'moment';
+  import * as Utils from '@/utils';
+  export default {
+    name: 'CommonStaticTable',
+    props: {
+      value: {
+        type: Array,
+        default: () => []
+      },
+      spanMethod: {
+        type: Function,
+        default: null
+      },
+      data: {
+        type: Array,
+        default: () => []
+      },
+      initSelected: {
+        type: Array,
+        default: () => []
+      },
+      // eslint-disable-next-line vue/require-prop-types
+      maxHeight: {
+        default: 700
+      },
+      stripe: {
+        type: Boolean,
+        default: true
+      },
+      fit: {
+        type: Boolean,
+        default: true
+      },
+      highlightCurrentRow: {
+        type: Boolean,
+        default: true
+      },
+      showOverflowTooltip: {
+        type: Boolean,
+        default: true
+      },
+      border: {
+        type: Boolean,
+        default: false
+      },
+      emptyText: {
+        type: String,
+        default: '暂无数据'
+      },
+      topLayout: {
+        type: Array,
+        default: () => {
+          return ['left', 'right'];
+        }
+      },
+      bottomLayout: {
+        type: Array,
+        default: () => {
+          return ['left', 'right'];
+        }
+      },
+      fields: {
+        // 后端返回的字段
+        type: Array,
+        default: () => {
+          return [];
+        }
+      },
+      selection: {
+        // 开始开启多选(默认不开启, false)
+        type: Boolean,
+        default: false
+      },
+      // api 对象
+      api: {
+        type: Function,
+        default: null
+      },
+      params: {
+        type: Object,
+        default: () => {
+          return {};
+        }
+      }
+    },
+    data() {
+      return {
+        tableEditable: true,
+        showFields: [], // 显示的字段
+        filterFields: [], // 过滤的字段
+        filterPlaceholder: '过滤', // 过滤提示文字
+        buttonTagList: [], // 所有按钮标签
+        excelDialogVisible: false,
+        tableLoading: false,
+        advancedSearchForm: {},
+        advancedSearchFields: [],
+        rowKey: null,
+        multipleSelection: [],
+        excelHeader: [],
+        excelData: [],
+        searchForm: {
+          search: ''
+        },
+        getRowKeys: row => {
+          if (this.rowKey) {
+            return row[this.rowKey];
+          }
+          return row.id || row.uuid;
+        },
+        exportFields: [],
+        tableData: [],
+        filterData: [],
+        isFilter: false
+      };
+    },
+    computed: {
+      topLayoutLeft() {
+        return this.topLayout.indexOf('left') >= 0;
+      },
+      topLayoutRight() {
+        return this.topLayout.indexOf('right') >= 0;
+      }
+    },
+    watch: {
+      data: {
+        handler: function(newData, oldData) {
+          this.handleChangeTableData(newData);
+        },
+        immediate: true
+      }
+    },
+    mounted() {
+    },
+    created() {
+      this.initComponentData();
+      this.initData();
+      this.initSelect();
+    },
+    methods: {
+      initData() {
+        if (Utils.isFunction(this.api)) {
+          this.listInterfaceData();
+        }
+      },
+      initSelect() {
+        for (const row of this.initSelected) {
+          this.$refs['table'].toggleRowSelection(row, true);
+        }
+      },
+      initComponentData() {
+        this.fields.forEach(field => {
+          field.show = (!!field.show);
+          field.type = (field.type || 'string').toLocaleLowerCase();
+          field.label = field.label || field.prop;
+          field.search = (!!field.search);
+          field.sortable = (!!field.sortable);
+          field.unique = (!!field.unique);
+          field.width = field.width || '';
+          if (field.type === 'choices') {
+            if (Utils.isArray(field.choices) && field.choices.length > 0) {
+              if (!Utils.isObj(field.choices[0])) {
+                field.choices = field.choices.map(value => {
+                  return {
+                    label: value,
+                    value: value
+                  };
+                });
+              }
+            }
+          }
+          field.unique = (!!field.unique);
+          if (field.unique) {
+            this.rowKey = field.prop;
+          }
+        });
+        this.filterFields = this.fields.filter(field => field.search).map(field => field.prop);
+        if (this.filterFields.length) {
+          const text = this.fields.filter(field => field.search).map(field => field.label).join('、');
+          this.filterPlaceholder = `${text} 过滤`;
+        }
+      },
+      listInterfaceData() {
+        this.tableLoading = true;
+        this.api(this.params).then(response => {
+          this.tableLoading = false;
+          this.handleChangeTableData(response.data);
+        }).catch(() => {
+          this.tableLoading = false;
+        });
+      },
+      formatColumnData(row, field) {
+        const type = field.type || 'string';
+        const prop = field.prop;
+        if (field.formatter && typeof field.formatter === 'function') {
+          return field.formatter(row, prop, type);
+        }
+        if (type === 'string') {
+          return row[prop];
+        } else if (type === 'datetime') {
+          return this.formatDatetime(row[prop]);
+        } else if (type === 'date') {
+          return this.formatDate(row[prop]);
+        } else if (type === 'time') {
+          return this.formatTime(row[prop]);
+        } else if (type.startsWith('bool')) {
+          return row[prop] ? '是' : '否';
+        } else if (type === 'choices') {
+          const choices = field.choices;
+          return this.formatChoices(choices, row[prop]);
+        } else {
+          return row[prop];
+        }
+      },
+      formatChoices(choices, value) {
+        for (const choice of choices) {
+          if (choice.value === value) {
+            return choice.label;
+          }
+        }
+        return value;
+      },
+      formatDatetime(datetime) {
+        return moment(datetime).format('YYYY-MM-DD HH:mm:ss');
+      },
+      formatDate(date) {
+        return moment(date).format('YYYY-MM-DD');
+      },
+      formatTime(time) {
+        return moment(time).format('HH:mm:ss');
+      },
+      getMultipleSelection() {
+        return this.multipleSelection || [];
+      },
+      clearMultipleSelection() {
+        this.$refs.table.clearSelection();
+      },
+      clearSelection() {
+        this.$refs.table.clearSelection();
+      },
+      clearFilter() {
+        // 重置过滤
+        this.searchForm.search = '';
+        this.filterData = Array.from(this.tableData);
+      },
+      handleSelectField(e, field) {
+        field.show = e;
+      },
+      handleChangeTableData(data) {
+        this.tableData = Array.from(data);
+        this.filterData = Array.from(this.filterHandler(this.tableData));
+      },
+      // 导出表格的数据, 当前数据、当前列
+      handleExportTableData() {
+        this.excelDialogVisible = true;
+        this.exportFields = this.fields.map(field => {
+          return { prop: field.prop, label: field.label, show: field.show };
+        });
+        this.excelHeader = this.showFields.map(field => field['prop']);
+      },
+      // 处理修改多选的值
+      handleSelectionChange(val) {
+        this.$emit('selection-change', val);
+        this.multipleSelection = val;
+      },
+      handleSortChange(val) {
+        this.sort.prop = val.prop;
+        this.sort.order = val.order;
+        this.getTableData();
+      },
+      filterHandler(data) {
+        if (!data) {
+          data = this.tableData || [];
+        }
+        const search = this.searchForm.search.trim();
+        if (!search.length || !this.filterFields.length) {
+          this.isFilter = false;
+          return data;
+        }
+        const filterData = data.filter(row => {
+          for (const field of this.filterFields) {
+            if (row[field] && row[field].indexOf(search) >= 0) {
+              return true;
+            }
+          }
+          return false;
+        });
+        this.isFilter = true;
+        return filterData;
+      },
+      handleCellClick(row, column, cell, event) {
+        this.$emit('cell-click', row, column, cell, event);
+      },
+      handleCellDbClick(row, column, cell, event) {
+        this.$emit('cell-dblclick', row, column, cell, event);
+      },
+      handleRowClick(row, column, event) {
+        this.$emit('row-click', row, column, event);
+      },
+      handleRowDblClick(row, column, event) {
+        this.$emit('row-dblclick', row, column, event);
+      },
+      handleHeaderClick(column, event) {
+        this.$emit('header-click', column, event);
+      },
+      toggleRowSelection(row, selected = true) {
+        this.$refs.table.toggleRowSelection(row, selected);
+      },
+      toggleFilter() {
+        // 触发过滤
+        this.filterData = Array.from(this.filterHandler());
+      },
+      handleSearchFormSubmit() {
+        this.toggleFilter();
+      },
+      handleCancelFilter() {
+        this.isFilter = false;
+        this.clearFilter();
+      }
+    }
+  };
+</script>
+
+<style scoped>
+  .picker {
+    width: 240px;
+  }
+  .el-pagination {
+    padding: 5px;
+  }
+  .right_pagination {
+    text-align: right;
+    padding-top: 20px;
+  }
+</style>
diff --git a/dvadmin-ui/src/components/SmallDialog/index.vue b/dvadmin-ui/src/components/SmallDialog/index.vue
new file mode 100644
index 0000000..a5ced32
--- /dev/null
+++ b/dvadmin-ui/src/components/SmallDialog/index.vue
@@ -0,0 +1,119 @@
+<!--
+@description: 已封装组件、通用组件、基础组件、全局组件(已注册全局组件)
+-->
+<template>
+  <el-dialog
+    ref="elDialog"
+    :visible.sync="visible"
+    :loading="loading"
+    :append-to-body="appendToBody"
+    :width="width"
+    :show-close="false"
+    :destroy-on-close="destroyOnClose"
+    :close-on-click-modal="closeOnClickModal"
+    class="small-dialog"
+    @open="open"
+    @opened="opened"
+    @close="close"
+    @closed="closed"
+  >
+    <el-row slot="title">
+      <el-col :span="18" style="text-align: left;">
+        <common-icon :icon-title="dialogTitle || 'Dialog组件'" :value="icon" style="font-size: 1.2em"/>
+      </el-col>
+      <el-col :span="6" style="text-align: right">
+        <i class="el-icon-close" style="font-size: 30px; cursor: pointer" title="关闭" @click="dialogClose"/>
+      </el-col>
+    </el-row>
+    <div class="dialog-body">
+      <slot/>
+    </div>
+    <slot name="footer">
+      <div class="dialog-button">
+        <el-button v-if="buttons.indexOf('cancel') >= 0" :size="size" :disabled="loading" type="info" title="取消" @click="cancel">取消</el-button>
+        <el-button v-if="buttons.indexOf('confirm') >= 0" :size="size" :disabled="loading" type="success" title="确定" @click="confirm">确定</el-button>
+      </div>
+    </slot>
+  </el-dialog>
+
+</template>
+<script>
+  export default {
+    name: 'SmallDialog',
+    props: {
+      value: { type: Boolean, default: false },
+      dialogTitle: { type: String, default: '' },
+      width: { type: String, default: '50%' },
+      icon: { type: String, default: 'el:el-icon-platform-eleme' },
+      buttons: { type: Array, default: () => ['cancel', 'confirm'] },
+      loading: { type: Boolean, default: false },
+      appendToBody: { type: Boolean, default: false },
+      destroyOnClose: { type: Boolean, default: false },
+      closeOnClickModal: { type: Boolean, default: true }
+    },
+    data() {
+      return {
+        visible: false,
+        size: null
+      };
+    },
+    watch: {
+      value(val) {
+        this.visible = val;
+      },
+      visible(val) {
+        this.$emit('input', val);
+      }
+    },
+    created() {
+    },
+    methods: {
+      open() {
+        this.$emit('open');
+      },
+      opened() {
+        this.$emit('opened');
+      },
+      close() {
+        this.$emit('close');
+      },
+      closed() {
+        this.$emit('closed');
+      },
+      confirm() {
+        this.$emit('confirm');
+      },
+      cancel() {
+        this.$emit('cancel');
+        this.dialogClose();
+      },
+      dialogOpen() {
+      },
+      dialogClose() {
+        this.visible = false;
+      }
+    }
+  };
+</script>
+<style rel="stylesheet/scss" lang="scss">
+  .small-dialog {
+    .el-dialog__header {
+      padding: 5px;
+    }
+    .el-dialog__body {
+      padding: 5px;
+    }
+  }
+</style>
+<style rel="stylesheet/scss" lang="scss" scoped>
+  .small-dialog {
+    .dialog-body {
+      padding-top: 5px;
+    }
+    .dialog-button {
+      margin-top: 10px;
+      text-align: right;
+    }
+  }
+</style>
+
diff --git a/dvadmin-ui/src/main.js b/dvadmin-ui/src/main.js
index 8f90052..9037bb0 100755
--- a/dvadmin-ui/src/main.js
+++ b/dvadmin-ui/src/main.js
@@ -14,12 +14,24 @@ import permission from './directive/permission'
 
 import './assets/icons' // icon
 import './permission' // permission control
-import { getDicts } from "@/api/vadmin/system/dict/data";
-import { getConfigKey } from "@/api/vadmin/system/config";
-import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, download, handleTree } from "@/utils/ruoyi";
+import {getDicts} from "@/api/vadmin/system/dict/data";
+import {getConfigKey} from "@/api/vadmin/system/config";
+import {
+  addDateRange,
+  download,
+  handleTree,
+  parseTime,
+  resetForm,
+  selectDictLabel,
+  selectDictLabels
+} from "@/utils/ruoyi";
 import Pagination from "@/components/Pagination";
 // 自定义表格工具扩展
 import RightToolbar from "@/components/RightToolbar"
+import SmallDialog from '@/components/SmallDialog';
+import CommonIcon from '@/components/CommonIcon';
+import CommonStaticTable from '@/components/CommonStaticTable';
+import {getCrontabData, getIntervalData} from "./utils/validate"; // 通用图标组件
 
 // 全局方法挂载
 Vue.prototype.getDicts = getDicts
@@ -29,30 +41,35 @@ Vue.prototype.resetForm = resetForm
 Vue.prototype.addDateRange = addDateRange
 Vue.prototype.selectDictLabel = selectDictLabel
 Vue.prototype.selectDictLabels = selectDictLabels
+Vue.prototype.getCrontabData = getCrontabData
+Vue.prototype.getIntervalData = getIntervalData
 Vue.prototype.download = download
 Vue.prototype.handleTree = handleTree
 Vue.prototype.hasPermi = function (values) {
   const permissions = store.getters && store.getters.permissions
-  return  permissions.some(permission => {
+  return permissions.some(permission => {
     return "*:*:*" === permission || values.includes(permission)
   })
 };
 
 Vue.prototype.msgSuccess = function (msg) {
-  this.$message({ showClose: true, message: msg, type: "success" });
+  this.$message({showClose: true, message: msg, type: "success"});
 }
 
 Vue.prototype.msgError = function (msg) {
-  this.$message({ showClose: true, message: msg, type: "error" });
+  this.$message({showClose: true, message: msg, type: "error"});
 }
 
 Vue.prototype.msgInfo = function (msg) {
   this.$message.info(msg);
 }
-
+// 自定义组件
+Vue.component('small-dialog', SmallDialog);
 // 全局组件挂载
 Vue.component('Pagination', Pagination)
 Vue.component('RightToolbar', RightToolbar)
+Vue.component('common-icon', CommonIcon);
+Vue.component('common-static-table', CommonStaticTable);
 
 Vue.use(permission)
 
diff --git a/dvadmin-ui/src/router/index.js b/dvadmin-ui/src/router/index.js
index e13fbab..9b9ad26 100755
--- a/dvadmin-ui/src/router/index.js
+++ b/dvadmin-ui/src/router/index.js
@@ -98,6 +98,18 @@ export const constantRoutes = [
         meta: { title: '字典数据', icon: '' }
       }
     ]
+  },{
+    path: '/celerymanage',
+    component: Layout,
+    hidden: false,
+    children: [
+      {
+        path: 'celerymanage',
+        component: (resolve) => require(['@/views/vadmin/monitor/celery/index'], resolve),
+        name: 'Data',
+        meta: { title: 'celery管理', icon: '' }
+      }
+    ]
   }
 ]
 
diff --git a/dvadmin-ui/src/utils/index.js b/dvadmin-ui/src/utils/index.js
index 918580f..60fa980 100755
--- a/dvadmin-ui/src/utils/index.js
+++ b/dvadmin-ui/src/utils/index.js
@@ -5,12 +5,12 @@ import { parseTime } from './ruoyi'
  */
 export function formatDate(cellValue) {
   if (cellValue == null || cellValue == "") return "";
-  var date = new Date(cellValue) 
+  var date = new Date(cellValue)
   var year = date.getFullYear()
   var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
-  var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() 
-  var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours() 
-  var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() 
+  var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
+  var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
+  var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
   var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
   return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
 }
@@ -330,7 +330,7 @@ export function makeMap(str, expectsLowerCase) {
     ? val => map[val.toLowerCase()]
     : val => map[val]
 }
- 
+
 export const exportDefault = 'export default '
 
 export const beautifierConf = {
@@ -387,4 +387,18 @@ export function camelCase(str) {
 export function isNumberStr(str) {
   return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
 }
- 
+
+// 是否函数
+export const isFunction = (o) => {
+  return Object.prototype.toString.call(o).slice(8, -1) === 'Function';
+};
+
+// 是否数组
+export const isArray = (o) => {
+  return Object.prototype.toString.call(o).slice(8, -1) === 'Array';
+};
+
+// 是否对象
+export const isObj = (o) => {
+  return Object.prototype.toString.call(o).slice(8, -1) === 'Object';
+};
diff --git a/dvadmin-ui/src/utils/validate.js b/dvadmin-ui/src/utils/validate.js
index adfa254..55e35b8 100755
--- a/dvadmin-ui/src/utils/validate.js
+++ b/dvadmin-ui/src/utils/validate.js
@@ -81,3 +81,29 @@ export function isArray(arg) {
   }
   return Array.isArray(arg)
 }
+
+export function getCrontabData(val) {
+  if (!val || Object.keys(val).length === 0) return '';
+  const week = {1: '一', 2: '二', 3: '三', 4: '四', 5: '五', 6: '六', 7: '日'};
+  let res = '';
+  if (val.month_of_year !== '*') {
+    res = `${val.month_of_year} 月 ${val.day_of_month} 日 ${val.hour}点${val.minute}分`;
+  } else if (val.day_of_month !== '*') {
+    res = `每月 ${val.day_of_month} 日 ${val.hour}点${val.minute}分`;
+  } else if (val.day_of_week !== '*') {
+    res = `每周周${week[val.day_of_week] || val.day_of_week} ${val.hour}点${val.minute}分 `;
+  } else if (val.hour !== '*') {
+    res = `每天 ${val.hour}点${val.minute}分`;
+  } else if (val.minute !== '*') {
+    res = `每分钟 ${val.minute}秒`;
+  } else {
+    res = `${val.month_of_year} 月 ${val.day_of_month} 日 ${val.hour}点${val.minute}分`;
+  }
+  return res.replace(/\*/g, '00');
+}
+
+export function getIntervalData(val) {
+  if (!val || Object.keys(val).length === 0) return '';
+  const lists = {days: '天', hours: '小时', seconds: '秒', minutes: '分钟'};
+  return `每${val.every !== 1 ? val.every : ''}${lists[val.period]}`;
+}
diff --git a/dvadmin-ui/src/views/vadmin/monitor/celery/crontab-task/crontab-index.vue b/dvadmin-ui/src/views/vadmin/monitor/celery/crontab-task/crontab-index.vue
new file mode 100644
index 0000000..c49d01a
--- /dev/null
+++ b/dvadmin-ui/src/views/vadmin/monitor/celery/crontab-task/crontab-index.vue
@@ -0,0 +1,160 @@
+<!--
+@author: xuchi
+@description: 接口信息页面
+-->
+<template>
+  <div class="app-container">
+    <el-card class="box-card" shadow="never">
+      <div slot="header" class="clearfix">
+        <span>任务定时</span>
+        <el-button style="float: right; padding: 3px 0" type="text" @click="handleOpenEditCrontabForm(true)">
+          新增定时
+        </el-button>
+      </div>
+      <div style="height: 200px;">
+        <el-scrollbar>
+          <div v-for="(val,index) in detail" :key="index">
+            <div class="text" style="display:inline-block;height: 10px;">
+              <span>{{ getCrontabData(val) }}</span>
+            </div>
+            <div style="float: right;padding-right: 10px;display:inline-block">
+              <el-button
+                type="primary"
+                icon="el-icon-edit"
+                size="mini"
+                circle
+                @click="handleOpenEditCrontabForm(false, val)"/>
+              <el-button
+                type="danger"
+                icon="el-icon-delete"
+                size="mini"
+                circle
+                @click="handleRemoveCrontabTable(val)"/>
+            </div>
+            <el-divider/>
+          </div>
+          <div v-if="detail.length===0" style="text-align: center">
+            暂无信息
+          </div>
+        </el-scrollbar>
+      </div>
+    </el-card>
+    <edit-form-crontab-task
+      v-model="editCrontabFormVisible"
+      :entity="editCrontab"
+      :create="editCrontabCreate"
+      :periodic-data="periodicData"
+      :width="'30%'"
+      @success="handleSuccessEditCrontab"/>
+  </div>
+</template>
+
+<script>
+  import * as SyncDataApi from "@/api/vadmin/monitor/celery";
+  import EditFormCrontabTask from './edit-form-crontab-task';
+
+  export default {
+    components: { EditFormCrontabTask },
+    props: {
+    },
+    data() {
+      return {
+        periodicData: [],
+        multipleSelection: [],
+        CrontabTagList: [],
+        editCrontab: {},
+        editCrontabFormVisible: false,
+        editCrontabCreate: false,
+        modelFormVisible: false,
+        modelSwaggerVisible: false,
+        batchEditFormVisible: false,
+        detail: []
+      };
+    },
+    computed: {
+    },
+    watch: {
+    },
+    created() {
+      this.initData();
+    },
+    methods: {
+      initData() {
+        SyncDataApi.listCrontabSchedule({ page_size: 1000 }).then((response) => {
+          this.detail = response.data.results || [];
+          this.$store.state.Crontab = this.detail;
+        });
+      },
+      handleRefresh(infos) {
+        this.$refs.table.clearSelection();
+        this.$emit('update');
+      },
+      handleOpenEditCrontabForm(create = false, info) {
+        if (create) {
+          this.editCrontab = { periodic: this.detail.id };
+        } else {
+          this.editCrontab = { ...info };
+        }
+        this.editCrontabCreate = create;
+        this.editCrontabFormVisible = true;
+      },
+      handleRemoveCrontabTable(info) {
+        this.$confirm('确认删除?', '确认信息', {
+          distinguishCancelAndClose: true,
+          confirmButtonText: '删除',
+          cancelButtonText: '取消'
+        }).then(() => {
+          SyncDataApi.deleteCrontabSchedule(info.id).then(response => {
+            const name = info.name ? info.name + ':' : '';
+            this.msgSuccess(name + '删除成功!');
+            this.initData();
+          });
+        });
+      },
+      handleSuccessEditCrontab() {
+        this.$emit('update');
+      },
+      handleOpenModelForm() {
+        this.modelFormVisible = true;
+      },
+      handleOpenSwagger(model = false) {
+        this.modelSwaggerVisible = true;
+      },
+      handleBatchEdit() {
+        this.batchEditFormVisible = true;
+      }
+    }
+  };
+</script>
+
+<style scoped>
+  .el-table th {
+    display: table-cell !important;
+  }
+  .el-scrollbar {
+      height: 100%;
+  }
+
+  .el-scrollbar__wrap {
+      overflow: scroll;
+      width: 100%;
+      height: 100%;
+  }
+
+  .el-scrollbar__view {
+      height: 100%;
+  }
+
+  .el-divider--horizontal {
+      margin: 14px 0;
+  }
+
+  .text {
+      padding-left: 20px;
+      font-size: 14px;
+  }
+  .el-button--mini.is-circle {
+      padding: 5px;
+
+  }
+</style>
diff --git a/dvadmin-ui/src/views/vadmin/monitor/celery/crontab-task/edit-form-crontab-task.vue b/dvadmin-ui/src/views/vadmin/monitor/celery/crontab-task/edit-form-crontab-task.vue
new file mode 100644
index 0000000..de433dd
--- /dev/null
+++ b/dvadmin-ui/src/views/vadmin/monitor/celery/crontab-task/edit-form-crontab-task.vue
@@ -0,0 +1,122 @@
+<!--
+@author: xuchi
+@description: 接口编辑组件
+-->
+<template>
+  <small-dialog
+    ref="dialog"
+    v-model="dialogVisible"
+    :dialog-title="dialogTitle"
+    :width="width"
+    icon="svg:icon-interface"
+    @confirm="handleSubmit"
+    @closed="dialogClose"
+    @opened="dialogOpen">
+    <el-form v-loading="loading" ref="form" :model="form" :size="$ELEMENT.size" label-width="120px">
+      <el-form-item v-show="false" prop="instanceId" label="instanceId" style="width: 200px;">
+        <el-input v-model="form.instanceId" readonly/>
+      </el-form-item>
+      <el-form-item prop="minute" label="分钟:">
+        <el-input v-model="form.minute" placeholder="默认: * "/>
+      </el-form-item>
+      <el-form-item prop="hour" label="小时:">
+        <el-input v-model="form.hour" placeholder="默认: * "/>
+      </el-form-item>
+      <el-form-item prop="day_of_week" label="每周的周几">
+        <el-input v-model="form.day_of_week" placeholder="默认: * "/>
+      </el-form-item>
+      <el-form-item prop="day_of_month" label="每月的某天">
+        <el-input v-model="form.day_of_month" placeholder="默认: * "/>
+      </el-form-item>
+      <el-form-item prop="month_of_year" label="每年的某月">
+        <el-input v-model="form.month_of_year" placeholder="默认: * "/>
+      </el-form-item>
+    </el-form>
+  </small-dialog>
+</template>
+<script>
+  import * as SyncDataApi from "@/api/vadmin/monitor/celery";
+  export default {
+    props: {
+      entity: { type: Object, default: null },
+      value: { type: Boolean, default: null },
+      create: { type: Boolean, default: false },
+      width: { type: String, default: '50%' },
+      tags: { type: Array, default: () => [] }
+    },
+    data() {
+      return {
+        loading: false,
+        dialogVisible: false,
+        form: {
+          instanceId: '',
+          minute: '*',
+          hour: '*',
+          day_of_week: '*',
+          day_of_month: '*',
+          month_of_year: '*'
+        }
+      };
+    },
+    computed: {
+      dialogTitle() {
+        return this.create ? '新增任务定时' : '编辑任务定时';
+      }
+    },
+    watch: {
+      value(val) {
+        this.dialogVisible = val;
+      },
+      dialogVisible(val) {
+        this.$emit('input', val);
+      }
+    },
+    created() {
+    },
+    methods: {
+      dialogOpen() {
+        // 为True意味着是通过遍及方式打开对话框
+        if (!this.create) {
+          this.form = { ...this.entity };
+        }
+      },
+      handleSubmit() {
+        this.$refs['form'].validate((valid) => {
+          if (valid) {
+            this.loading = true;
+            const data = { ...this.form };
+            console.log(this.form);
+            if (this.create) {
+              delete data['instanceId'];
+              SyncDataApi.createCrontabSchedule(data).then(response => {
+                this.loading = false;
+                this.$emit('success', response.data);
+                this.dialogClose();
+                this.msgSuccess('新增成功!');
+              }).catch(() => {
+                this.loading = false;
+              });
+            } else {
+              SyncDataApi.updateCrontabSchedule(data).then(response => {
+                this.$emit('success', response.data);
+                this.loading = false;
+                this.msgSuccess('更新成功!');
+                this.dialogClose();
+              }).catch(() => {
+                this.loading = false;
+              });
+            }
+          } else {
+            return false;
+          }
+        });
+      },
+      dialogClose() {
+        this.$refs['form'].resetFields();
+        this.$parent.initData();
+        this.dialogVisible = false;
+      }
+    }
+  };
+</script>
+
diff --git a/dvadmin-ui/src/views/vadmin/monitor/celery/index.vue b/dvadmin-ui/src/views/vadmin/monitor/celery/index.vue
new file mode 100644
index 0000000..f1a8a28
--- /dev/null
+++ b/dvadmin-ui/src/views/vadmin/monitor/celery/index.vue
@@ -0,0 +1,40 @@
+<!--
+@author: xuchi
+@description: 应用列表页面
+-->
+<template>
+  <div>
+    <el-row>
+      <el-col :span="8">
+        <interval-index/>
+      </el-col>
+      <el-col :span="8">
+        <crontabe-index/>
+      </el-col>
+    </el-row>
+    <periodic-task/>
+  </div>
+</template>
+<script>
+  import PeriodicTask from './periodic-task/periodic-index';
+  import IntervalIndex from './interval-task/interval-index';
+  import CrontabeIndex from './crontab-task/crontab-index';
+  export default {
+    components: { IntervalIndex, PeriodicTask, CrontabeIndex },
+    props: {},
+    data() {
+      return {};
+    },
+    mounted() {
+    },
+    created() {
+    },
+    methods: {}
+  };
+</script>
+
+<style scoped>
+  .el-table th {
+    display: table-cell !important;
+  }
+</style>
diff --git a/dvadmin-ui/src/views/vadmin/monitor/celery/interval-task/edit-form-Interval-task.vue b/dvadmin-ui/src/views/vadmin/monitor/celery/interval-task/edit-form-Interval-task.vue
new file mode 100644
index 0000000..8805172
--- /dev/null
+++ b/dvadmin-ui/src/views/vadmin/monitor/celery/interval-task/edit-form-Interval-task.vue
@@ -0,0 +1,124 @@
+<!--
+@author: xuchi
+@description: 接口编辑组件
+-->
+<template>
+  <small-dialog
+    ref="dialog"
+    v-model="dialogVisible"
+    :dialog-title="dialogTitle"
+    :width="width"
+    icon="svg:icon-interface"
+    @confirm="handleSubmit"
+    @closed="dialogClose"
+    @opened="dialogOpen">
+    <el-form v-loading="loading" ref="form" :model="form" :size="$ELEMENT.size" label-width="120px">
+      <el-form-item v-show="false" prop="instanceId" label="instanceId" style="width: 200px;">
+        <el-input v-model="form.instanceId" readonly/>
+      </el-form-item>
+      <el-form-item prop="every" label="频率:">
+        <el-input-number v-model="form.every" :min="1" label="频率"/>
+      </el-form-item>
+      <el-form-item prop="period" label="周期:">
+        <el-select v-model="form.period" placeholder="请选择">
+          <el-option
+            v-for="(item,index) in lists"
+            :key="index.value"
+            :label="item.label"
+            :value="item.value"/>
+        </el-select>
+      </el-form-item>
+    </el-form>
+  </small-dialog>
+</template>
+<script>
+  import * as SyncDataApi from "@/api/vadmin/monitor/celery";
+
+  export default {
+    props: {
+      entity: {type: Object, default: null},
+      value: {type: Boolean, default: null},
+      create: {type: Boolean, default: false},
+      width: {type: String, default: '50%'},
+      tags: {type: Array, default: () => []}
+    },
+    data() {
+      return {
+        lists: [
+          {label: '天', value: 'days'},
+          {label: '小时', value: 'hours'},
+          {label: '分钟', value: 'minutes'},
+          {label: '秒', value: 'seconds'}
+        ],
+        loading: false,
+        dialogVisible: false,
+        form: {
+          instanceId: '',
+          every: 1,
+          period: '',
+          title: ''
+        }
+      };
+    },
+    computed: {
+      dialogTitle() {
+        return this.create ? '新增任务频率' : '编辑任务频率';
+      }
+    },
+    watch: {
+      value(val) {
+        this.dialogVisible = val;
+      },
+      dialogVisible(val) {
+        this.$emit('input', val);
+      }
+    },
+    created() {
+    },
+    methods: {
+      dialogOpen() {
+        // 为True意味着是通过遍及方式打开对话框
+        if (!this.create) {
+          this.form = {...this.entity};
+        }
+      },
+      handleSubmit() {
+        this.$refs['form'].validate((valid) => {
+          if (valid) {
+            this.loading = true;
+            const data = {...this.form};
+            console.log(this.form);
+            if (this.create) {
+              delete data['instanceId'];
+              SyncDataApi.createIntervalschedule(data).then(response => {
+                this.loading = false;
+                this.$emit('success', response.data);
+                this.dialogClose();
+                this.msgSuccess('新增成功!');
+              }).catch(() => {
+                this.loading = false;
+              });
+            } else {
+              SyncDataApi.updateIntervalschedule(data).then(response => {
+                this.$emit('success', response.data);
+                this.loading = false;
+                this.msgSuccess('更新成功!');
+                this.dialogClose();
+              }).catch(() => {
+                this.loading = false;
+              });
+            }
+          } else {
+            return false;
+          }
+        });
+      },
+      dialogClose() {
+        this.$refs['form'].resetFields();
+        this.$parent.initData();
+        this.dialogVisible = false;
+      }
+    }
+  };
+</script>
+
diff --git a/dvadmin-ui/src/views/vadmin/monitor/celery/interval-task/interval-index.vue b/dvadmin-ui/src/views/vadmin/monitor/celery/interval-task/interval-index.vue
new file mode 100644
index 0000000..ff561b7
--- /dev/null
+++ b/dvadmin-ui/src/views/vadmin/monitor/celery/interval-task/interval-index.vue
@@ -0,0 +1,161 @@
+<!--
+@author: xuchi
+@description: 接口信息页面
+-->
+<template>
+  <div class="app-container">
+    <el-card class="box-card" shadow="never">
+      <div slot="header" class="clearfix">
+        <span>任务频率</span>
+        <el-button style="float: right; padding: 3px 0" type="text" @click="handleOpenEditIntervalForm(true)">
+          新增频率
+        </el-button>
+      </div>
+      <div style="height: 200px;">
+        <el-scrollbar>
+          <div v-for="(val,index) in detail" :key="index">
+            <div class="text" style="display:inline-block;height: 10px;">
+              {{ getIntervalData(val) }}
+            </div>
+            <div style="float: right;padding-right: 10px;display:inline-block">
+              <el-button
+                type="primary"
+                icon="el-icon-edit"
+                size="mini"
+                circle
+                @click="handleOpenEditIntervalForm(false, val)"/>
+              <el-button
+                type="danger"
+                icon="el-icon-delete"
+                size="mini"
+                circle
+                @click="handleRemoveIntervalTable(val)"/>
+            </div>
+            <el-divider/>
+          </div>
+          <div v-if="detail.length===0" style="text-align: center">
+            暂无信息
+          </div>
+        </el-scrollbar>
+      </div>
+    </el-card>
+    <edit-form-interval-task
+      v-model="editIntervalFormVisible"
+      :entity="editInterval"
+      :create="editIntervalCreate"
+      :periodic-data="periodicData"
+      :width="'30%'"
+      @success="handleSuccessEditInterval"/>
+  </div>
+</template>
+
+<script>
+    import * as SyncDataApi from "@/api/vadmin/monitor/celery";
+    import EditFormIntervalTask from './edit-form-Interval-task';
+
+    export default {
+        components: { EditFormIntervalTask },
+        props: {},
+        data() {
+            return {
+                periodicData: [],
+                multipleSelection: [],
+                IntervalTagList: [],
+                editInterval: {},
+                editIntervalFormVisible: false,
+                editIntervalCreate: false,
+                modelFormVisible: false,
+                modelSwaggerVisible: false,
+                batchEditFormVisible: false,
+                detail: []
+            };
+        },
+        computed: {},
+        watch: {},
+        created() {
+            this.initData();
+        },
+        methods: {
+            initData() {
+                SyncDataApi.listIntervalschedule({ page_size: 1000 }).then((response) => {
+                    this.detail = response.data.results || [];
+                    this.$store.state.Interval = this.detail;
+                });
+            },
+            handleRefresh(infos) {
+                this.$refs.table.clearSelection();
+                this.$emit('update');
+            },
+            handleIntervalSelectionChange(infos) {
+                this.multipleSelection = infos;
+            },
+            handleOpenEditIntervalForm(create = false, info) {
+                if (create) {
+                    this.editInterval = { periodic: this.detail.id };
+                } else {
+                    this.editInterval = { ...info };
+                }
+                this.editIntervalCreate = create;
+                this.editIntervalFormVisible = true;
+            },
+            handleRemoveIntervalTable(info) {
+                this.$confirm('确认删除?', '确认信息', {
+                    distinguishCancelAndClose: true,
+                    confirmButtonText: '删除',
+                    cancelButtonText: '取消'
+                }).then(() => {
+                    SyncDataApi.deleteIntervalschedule(info.id).then(response => {
+                        const name = info.name ? info.name + ':' : '';
+                        this.msgSuccess(name + '删除成功');
+                        this.initData();
+                    });
+                });
+            },
+            handleSuccessEditInterval() {
+                this.$emit('update');
+            },
+            handleOpenModelForm() {
+                this.modelFormVisible = true;
+            },
+            handleOpenSwagger(model = false) {
+                this.modelSwaggerVisible = true;
+            },
+            handleBatchEdit() {
+                this.batchEditFormVisible = true;
+            }
+        }
+    };
+</script>
+
+<style scoped>
+    .el-table th {
+        display: table-cell !important;
+    }
+
+    .el-scrollbar {
+        height: 100%;
+    }
+
+    .el-scrollbar__wrap {
+        overflow: scroll;
+        width: 100%;
+        height: 100%;
+    }
+
+    .el-scrollbar__view {
+        height: 100%;
+    }
+
+    .el-divider--horizontal {
+        margin: 14px 0;
+    }
+
+    .text {
+        padding-left: 20px;
+        font-size: 14px;
+    }
+    .el-button--mini.is-circle {
+        padding: 5px;
+
+    }
+</style>
diff --git a/dvadmin-ui/src/views/vadmin/monitor/celery/periodic-task/edit-form-periodic-task.vue b/dvadmin-ui/src/views/vadmin/monitor/celery/periodic-task/edit-form-periodic-task.vue
new file mode 100644
index 0000000..b402cda
--- /dev/null
+++ b/dvadmin-ui/src/views/vadmin/monitor/celery/periodic-task/edit-form-periodic-task.vue
@@ -0,0 +1,191 @@
+<!--
+@author: xuchi
+@description: 接口编辑组件
+-->
+<template>
+  <small-dialog
+    ref="dialog"
+    v-model="dialogVisible"
+    :dialog-title="dialogTitle"
+    :width="width"
+    :close-on-click-modal="false"
+    :append-to-body="true"
+    icon="svg:icon-interface"
+    @confirm="handleSubmit"
+    @closed="dialogClose"
+    @opened="dialogOpen">
+    <el-form v-loading="loading" ref="form" :model="form" :size="$ELEMENT.size" label-width="120px">
+      <el-form-item :rules="[{ required: true, message: '任务不能为空'}]" label="celery任务:" prop="task">
+        <el-autocomplete
+          v-model="form.task"
+          :fetch-suggestions="querySearch"
+          class="inline-input"
+          filterable
+          placeholder="celery任务"
+          style="width: 400px;"
+          @select="handleSelect"
+        >
+          <template slot-scope="{ item }">
+            <div class="name">{{ item }}</div>
+          </template>
+        </el-autocomplete>
+      </el-form-item>
+      <el-form-item :rules="[{ required: true, message: '名称不能为空'}]" prop="name" label="名称:">
+        <el-input v-model="form.name" placeholder="例如: 主机表同步任务" style="width: 400px;"/>
+      </el-form-item>
+      <el-form-item prop="interval" label="任务频率:">
+        <el-select v-model="form.interval" placeholder="请选择任务频率" style="width: 400px;" @change="form.crontab = ''">
+          <el-option
+            v-for="(item,index) in Interval"
+            :key="index"
+            :label="getIntervalData(item)"
+            :value="item.id"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item prop="crontab" label="任务定时:">
+        <el-select v-model="form.crontab" placeholder="请选择任务定时" style="width: 400px;" @change="form.interval = ''">
+          <el-option
+            v-for="(item,index) in Crontab"
+            :key="index"
+            :label="getCrontabData(item)"
+            :value="item.id"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item prop="enabled" label="是否开启:">
+        <template>
+          <el-radio-group v-model="form.enabled">
+            <el-radio :label="true">是</el-radio>
+            <el-radio :label="false">否</el-radio>
+          </el-radio-group>
+        </template>
+      </el-form-item>
+    </el-form>
+  </small-dialog>
+</template>
+<script>
+  import * as SyncDataApi from "@/api/vadmin/monitor/celery";
+  export default {
+    props: {
+      entity: { type: Object, default: null },
+      value: { type: Boolean, default: null },
+      create: { type: Boolean, default: false },
+      width: { type: String, default: '50%' },
+      tags: { type: Array, default: () => [] }
+    },
+    data() {
+        return {
+            loading: false,
+            dialogVisible: false,
+            form: {
+                task: '',
+                name: '',
+                interval: '',
+                crontab: '',
+                date: '',
+                enabled: false
+            },
+            tasks_as_choices: [],
+            Crontab: [],
+            Interval: []
+        };
+    },
+    computed: {
+      dialogTitle() {
+        return this.create ? '新增任务' : '编辑任务';
+      }
+    },
+    watch: {
+      value(val) {
+        this.dialogVisible = val;
+      },
+      dialogVisible(val) {
+        this.$emit('input', val);
+        if (!this.Crontab[0]) {
+          this.Crontab = this.$store.state.Crontab;
+          console.log(1, this.Crontab);
+        }
+        if (!this.Interval[0]) {
+          this.Interval = this.$store.state.Interval;
+          console.log(2, this.Interval);
+        }
+      }
+    },
+    created() {
+      // 获取所有 tasks 名称
+      SyncDataApi.TasksAsChoices().then((response) => {
+        this.tasks_as_choices = response.data || [];
+      });
+    },
+    methods: {
+      querySearch(queryString, cb) {
+        var restaurants = this.tasks_as_choices;
+        var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
+        // 调用 callback 返回建议列表的数据
+        cb(results);
+      }, createFilter(queryString) {
+        return (restaurant) => {
+          return (restaurant.toLowerCase().indexOf(queryString.toLowerCase()) !== -1);
+        };
+      },
+      handleSelect(item) {
+        this.form.task = item;
+      },
+      dialogOpen() {
+        // 为True意味着是通过遍及方式打开对话框
+        if (!this.create) {
+          this.form = { ...this.entity };
+        }
+      },
+      handleSubmit() {
+        this.$refs['form'].validate((valid) => {
+          if (valid) {
+            this.loading = true;
+            const data = { ...this.form };
+            if (this.create) {
+              delete data['instanceId'];
+              SyncDataApi.createPeriodicTask(data).then(response => {
+                this.loading = false;
+                this.$emit('success', response.data);
+                this.dialogClose();
+                this.msgSuccess('新增成功!');
+              }).catch(() => {
+                this.loading = false;
+              });
+            } else {
+              SyncDataApi.updatePeriodicTask(data).then(response => {
+                this.$emit('success', response.data);
+                this.loading = false;
+                this.msgSuccess('更新成功!');
+                this.dialogClose();
+              }).catch(() => {
+                this.loading = false;
+              });
+            }
+          } else {
+            return false;
+          }
+        });
+      },
+      dialogClose() {
+        this.$refs['form'].resetFields();
+        this.dialogVisible = false;
+      }
+    }
+  };
+</script>
+<style>
+    .el-picker-panel {
+        color: #606266;
+        border: 1px solid #E4E7ED;
+        -webkit-box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
+        box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
+        background: #FFF;
+        border-radius: 4px;
+        line-height: 5px!important;
+        margin: 5px 0;
+    }
+    .el-picker-panel__content {
+         margin: 15px;
+    }
+</style>
+
diff --git a/dvadmin-ui/src/views/vadmin/monitor/celery/periodic-task/periodic-index.vue b/dvadmin-ui/src/views/vadmin/monitor/celery/periodic-task/periodic-index.vue
new file mode 100644
index 0000000..9946adf
--- /dev/null
+++ b/dvadmin-ui/src/views/vadmin/monitor/celery/periodic-task/periodic-index.vue
@@ -0,0 +1,218 @@
+<!--
+@description: 接口信息页面
+-->
+<template>
+  <div class="app-container">
+    <common-static-table
+      ref="table"
+      :data="detail"
+      :fields="fields"
+      selection
+      @selection-change="handlePeriodicSelectionChange"
+    >
+      <template v-slot:enabled="scope">
+        <el-switch
+          :value="scope.values[scope.prop]"
+          active-color="#13ce66"
+          disabled
+          inactive-color="#ff4949"/>
+      </template>
+      <template v-slot:interval="scope">
+        {{ getIntervalData(scope.values[`${scope.prop}_list`]) }}
+      </template>
+      <template v-slot:crontab="scope">
+        {{ getCrontabData(scope.values[`${scope.prop}_list`]) }}
+      </template>
+      <template slot="button">
+        <el-button
+          :size="$ELEMENT.size"
+          type="primary"
+          title="添加任务"
+          icon="el-icon-circle-plus"
+          @click="handleOpenEditPeriodicForm(true)">新增
+        </el-button>
+      </template>
+      <!--以下是自定义新增的工具栏内容-->
+      <template slot="tools">
+        <el-popover placement="bottom" title="温馨提示" width="400" trigger="click" style="margin-left: 10px">
+          <li>待编写</li>
+          <el-button
+            slot="reference"
+            name="refresh"
+            type="info"
+            size="small"
+            icon="el-icon-info"
+            title="温馨提示"/>
+        </el-popover>
+      </template>
+      <!--以下是自定义新增的列的配置内容-->
+      <template slot="column">
+        <el-table-column fixed="right" label="操作" align="center" width="150">
+          <template slot-scope="scope">
+            <el-button
+              :size="$ELEMENT.size"
+              type="primary"
+              title="立即执行"
+              icon="el-icon-caret-right"
+              circle
+              @click="test(scope.row)"/>
+            <el-button
+              :size="$ELEMENT.size"
+              type="primary"
+              title="编辑"
+              icon="el-icon-edit"
+              circle
+              @click="handleOpenEditPeriodicForm(false, scope.row)"/>
+            <el-button
+              :size="$ELEMENT.size"
+              type="danger"
+              title="移除"
+              icon="el-icon-delete"
+              circle
+              @click="handleRemovePeriodicTable(scope.$index, scope.row)"
+            />
+          </template>
+        </el-table-column>
+      </template>
+    </common-static-table>
+    <el-dialog :visible.sync="dialogFormVisible" title="请确认" >
+      <span>
+        正在同步:{{ row.task }}
+      </span>
+      <br>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogFormVisible = false">取 消</el-button>
+        <el-button type="primary" @click="handleOperate">确 定</el-button>
+      </div>
+    </el-dialog>
+    <edit-form-periodic-task
+      v-model="editPeriodicFormVisible"
+      :entity="editPeriodic"
+      :create="editPeriodicCreate"
+      :periodic-data="periodicData"
+      :width="'40%'"
+      @success="handleSuccessEditPeriodic"/>
+  </div>
+</template>
+
+<script>
+  import * as SyncDataApi from "@/api/vadmin/monitor/celery";
+  import EditFormPeriodicTask from './edit-form-periodic-task';
+
+  export default {
+    components: { EditFormPeriodicTask },
+    props: {
+    },
+    data() {
+      return {
+        fields: [
+          // prop,后端列名称, 必填; label,前端表头名称, 必填; 其他可有可无
+          { prop: 'name', label: '名称', show: true, unique: true },
+          { prop: 'task', label: 'celery任务', show: true, width: 400 },
+          { prop: 'interval', label: '频率', show: true, search: true },
+          { prop: 'crontab', label: '任务编排', show: true, search: true, sortable: true },
+          { prop: 'args', label: '参数', show: false, search: true, sortable: true, width: 80 },
+          { prop: 'kwargs', label: '位置参数', show: false, search: true, sortable: true },
+          { prop: 'queue', label: '队列', show: false, search: true, sortable: true },
+          { prop: 'exchange', label: '状态', show: false, search: true },
+          { prop: 'routing_key', label: '路由密钥', show: false, search: true },
+          { prop: 'expires', label: '过期时间', show: false, search: true, type: 'datetime' },
+          { prop: 'enabled', label: '是否开启', show: true, search: true }
+        ],
+        periodicData: [],
+        multipleSelection: [],
+        PeriodicTagList: [],
+        editPeriodic: {},
+        editPeriodicFormVisible: false,
+        editPeriodicCreate: false,
+        modelFormVisible: false,
+        modelSwaggerVisible: false,
+        batchEditFormVisible: false,
+        detail: [],
+        dialogFormVisible: false,
+        form: { name: '' },
+        formLabelWidth: '120px',
+        row: '',
+        reqloading: false,
+        task_id:''
+      };
+    },
+    computed: {
+    },
+    watch: {
+    },
+    created() {
+      this.initData();
+    },
+    methods: {
+      initData() {
+        SyncDataApi.listPeriodicTask({ page_size: 1000 }).then((response) => {
+          this.detail = response.data.results || [];
+        });
+      },
+      handleRefresh(infos) {
+        this.$refs.table.clearSelection();
+        this.$emit('update');
+      },
+      handlePeriodicSelectionChange(infos) {
+        this.multipleSelection = infos;
+      },
+      handleOpenEditPeriodicForm(create = false, info) {
+        if (create) {
+          this.editPeriodic = { periodic: this.detail.id };
+        } else {
+          this.editPeriodic = { ...info };
+        }
+        this.editPeriodicCreate = create;
+        this.editPeriodicFormVisible = true;
+      },
+      handleRemovePeriodicTable(index, info) {
+        this.$confirm('确认删除?', '确认信息', {
+          distinguishCancelAndClose: true,
+          confirmButtonText: '删除',
+          cancelButtonText: '取消'
+        }).then(() => {
+          SyncDataApi.deletePeriodicTask(info.id).then(response => {
+            const name = info.name ? info.name + ':' : '';
+            this.msgSuccess(name + '删除成功');
+            this.initData();
+          });
+        });
+      },
+      handleSuccessEditPeriodic() {
+        this.initData();
+        this.$emit('update');
+      },
+      handleOpenModelForm() {
+        this.modelFormVisible = true;
+      },
+      handleOpenSwagger(model = false) {
+        this.modelSwaggerVisible = true;
+      },
+      handleBatchEdit() {
+        this.batchEditFormVisible = true;
+      },
+      test(row) {
+        this.dialogFormVisible = true;
+        this.row = row;
+        this.DetailMsg = ''
+      },
+      handleOperate() {
+        this.dialogFormVisible = false
+        this.reqloading = true;
+        SyncDataApi.operatesyncdata({ celery_name: this.row.task }).then(response => {
+         this.task_id = response.data.task_id
+        })
+      },
+      closeView(){
+        this.reqloading = false
+      }
+    }
+  };
+</script>
+
+<style scoped>
+  .el-table th {
+    display: table-cell !important;
+  }
+</style>