diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
index 2afde67cd..da7474e99 100644
--- a/ruoyi-ui/package.json
+++ b/ruoyi-ui/package.json
@@ -79,8 +79,8 @@
   },
   "devDependencies": {
     "@babel/core": "7.0.0",
-    "@babel/register": "7.0.0",
     "@babel/parser": "^7.7.4",
+    "@babel/register": "7.0.0",
     "@vue/cli-plugin-babel": "3.5.3",
     "@vue/cli-plugin-eslint": "^3.9.1",
     "@vue/cli-plugin-unit-jest": "3.5.3",
diff --git a/ruoyi-ui/src/main.js b/ruoyi-ui/src/main.js
index a7b5a8fcb..68bd65330 100644
--- a/ruoyi-ui/src/main.js
+++ b/ruoyi-ui/src/main.js
@@ -26,7 +26,7 @@ import Video from 'video.js'
 // require videojs style
 import 'video.js/dist/video-js.css';
 import 'vue-video-player/src/custom-theme.css';
-
+import Print from '@/utils/print'
 // 全局方法挂载
 Vue.prototype.getDicts = getDicts
 Vue.prototype.getConfigKey = getConfigKey
@@ -40,6 +40,7 @@ Vue.prototype.handleTree = handleTree
 
 Vue.prototype.$video = Video
 Vue.use(VideoPlayer);
+Vue.use(Print);
 
 
 import LunarFullCalendar from "vue-lunar-full-calendar";
diff --git a/ruoyi-ui/src/permission.js b/ruoyi-ui/src/permission.js
index 33fb6d665..f3f1ef669 100644
--- a/ruoyi-ui/src/permission.js
+++ b/ruoyi-ui/src/permission.js
@@ -14,7 +14,7 @@ NProgress.configure({
 })
 
 //const whiteList = ['/login', '/auth-redirect', '/bind', '/register']
-const whiteList = ['/login']
+const whiteList = ['/login', '/experience/apply/', '/experience/result/', '/experience/content/', '/activity', 'week', 'month', ', term', 'play']
 
 router.beforeEach((to, from, next) => {
   NProgress.start()
@@ -64,9 +64,17 @@ router.beforeEach((to, from, next) => {
       }
     }
   } else {
-    //console.log(whiteList.indexOf(to.path));
     // 没有token
-    if (whiteList.indexOf(to.path) !== -1 ||to.path.indexOf("/experience/apply/") != -1||to.path.indexOf("/experience/result/") != -1||to.path.indexOf("/experience/content/") != -1||to.path.indexOf("/activity") != -1) {
+    // if (whiteList.indexOf(to.path) !== -1 ||to.path.indexOf("/experience/apply/") != -1||to.path.indexOf("/experience/result/") != -1||to.path.indexOf("/experience/content/") != -1||to.path.indexOf("/activity") != -1||to.path.indexOf("/week") != -1) {
+    let whiteBool = false;
+    for (let path of whiteList) {
+      // console.log(to.path.indexOf(path) > -1);
+      if (to.path.indexOf(path) > -1) {
+        whiteBool = true;
+        break;
+      }
+    }
+    if (whiteBool) {
       // 在免登录白名单,直接进入
       next()
     } else {
diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js
index 4c9ccc429..db666b8cd 100644
--- a/ruoyi-ui/src/router/index.js
+++ b/ruoyi-ui/src/router/index.js
@@ -65,6 +65,30 @@ export const constantRoutes = [{
       import('@/views/benyi/activity'),
     hidden: true
   },
+  {
+    path: '/week',
+    component: () =>
+      import('@/views/benyi/themeweekplan/table'),
+    hidden: true
+  },
+  {
+    path: '/month',
+    component: () =>
+      import('@/views/benyi/thememonthplan/table'),
+    hidden: true
+  },
+  {
+    path: '/term',
+    component: () =>
+      import('@/views/benyi/themetermplan/table'),
+    hidden: true
+  },
+  {
+    path: '/play',
+    component: () =>
+      import('@/views/benyi/planweek/table'),
+    hidden: true
+  },
   {
     path: '/experience/apply/:id(\\d+)',
     component: () =>
diff --git a/ruoyi-ui/src/utils/print.js b/ruoyi-ui/src/utils/print.js
new file mode 100644
index 000000000..2bc2d78ca
--- /dev/null
+++ b/ruoyi-ui/src/utils/print.js
@@ -0,0 +1,155 @@
+// 打印类属性、方法定义
+/* eslint-disable */
+const Print = function (dom, options) {
+  if (!(this instanceof Print)) return new Print(dom, options);
+
+  this.options = this.extend({
+    'noPrint': '.no-print'
+  }, options);
+
+  if ((typeof dom) === "string") {
+    this.dom = document.querySelector(dom);
+  } else {
+    this.isDOM(dom)
+    this.dom = this.isDOM(dom) ? dom : dom.$el;
+  }
+
+  this.init();
+};
+Print.prototype = {
+  init: function () {
+    var content = this.getStyle() + this.getHtml();
+    this.writeIframe(content);
+  },
+  extend: function (obj, obj2) {
+    for (var k in obj2) {
+      obj[k] = obj2[k];
+    }
+    return obj;
+  },
+
+  getStyle: function () {
+    var str = "",
+      styles = document.querySelectorAll('style,link');
+    for (var i = 0; i < styles.length; i++) {
+      str += styles[i].outerHTML;
+    }
+    str += "<style>" + (this.options.noPrint ? this.options.noPrint : '.no-print') + "{display:none;}</style>";
+
+    return str;
+  },
+
+  getHtml: function () {
+    var inputs = document.querySelectorAll('input');
+    var textareas = document.querySelectorAll('textarea');
+    var selects = document.querySelectorAll('select');
+
+    for (var k = 0; k < inputs.length; k++) {
+      if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
+        if (inputs[k].checked == true) {
+          inputs[k].setAttribute('checked', "checked")
+        } else {
+          inputs[k].removeAttribute('checked')
+        }
+      } else if (inputs[k].type == "text") {
+        inputs[k].setAttribute('value', inputs[k].value)
+      } else {
+        inputs[k].setAttribute('value', inputs[k].value)
+      }
+    }
+
+    for (var k2 = 0; k2 < textareas.length; k2++) {
+      if (textareas[k2].type == 'textarea') {
+        textareas[k2].innerHTML = textareas[k2].value
+      }
+    }
+
+    for (var k3 = 0; k3 < selects.length; k3++) {
+      if (selects[k3].type == 'select-one') {
+        var child = selects[k3].children;
+        for (var i in child) {
+          if (child[i].tagName == 'OPTION') {
+            if (child[i].selected == true) {
+              child[i].setAttribute('selected', "selected")
+            } else {
+              child[i].removeAttribute('selected')
+            }
+          }
+        }
+      }
+    }
+    // 包裹要打印的元素
+    // fix: https://github.com/xyl66/vuePlugs_printjs/issues/36
+    return this.wrapperRefDom(this.dom).outerHTML;
+  },
+  // 向父级元素循环,包裹当前需要打印的元素
+  // 防止根级别开头的 css 选择器不生效
+  wrapperRefDom: function (refDom) {
+    let prevDom = null
+    let currDom = refDom
+    while (currDom && currDom.tagName.toLowerCase() !== 'body') {
+      if (prevDom) {
+        let element = currDom.cloneNode(false)
+        element.appendChild(prevDom)
+        prevDom = element
+      } else {
+        prevDom = currDom.cloneNode(true)
+      }
+
+      currDom = currDom.parentElement
+    }
+
+    return currDom.tagName.toLowerCase() === 'body' ? currDom : prevDom
+  },
+
+  writeIframe: function (content) {
+    var w, doc, iframe = document.createElement('iframe'),
+      f = document.body.appendChild(iframe);
+    iframe.id = "myIframe";
+    //iframe.style = "position:absolute;width:0;height:0;top:-10px;left:-10px;";
+    iframe.setAttribute('style', 'position:absolute;width:0;height:0;top:-10px;left:-10px;');
+    w = f.contentWindow || f.contentDocument;
+    doc = f.contentDocument || f.contentWindow.document;
+    doc.open();
+    doc.write(content);
+    doc.close();
+    var _this = this
+    iframe.onload = function(){
+      _this.toPrint(w);
+      setTimeout(function () {
+        document.body.removeChild(iframe)
+      }, 100)
+    }
+  },
+
+  toPrint: function (frameWindow) {
+    try {
+      setTimeout(function () {
+        frameWindow.focus();
+        try {
+          if (!frameWindow.document.execCommand('print', false, null)) {
+            frameWindow.print();
+          }
+        } catch (e) {
+          frameWindow.print();
+        }
+        frameWindow.close();
+      }, 10);
+    } catch (err) {
+      console.log('err', err);
+    }
+  },
+  isDOM: (typeof HTMLElement === 'object') ?
+    function (obj) {
+      return obj instanceof HTMLElement;
+    } :
+    function (obj) {
+      return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
+    }
+};
+const MyPlugin = {}
+MyPlugin.install = function (Vue, options) {
+  // 4. 添加实例方法
+  Vue.prototype.$print = Print
+}
+export default MyPlugin
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/benyi/planweek/table.vue b/ruoyi-ui/src/views/benyi/planweek/table.vue
new file mode 100644
index 000000000..5a55a713c
--- /dev/null
+++ b/ruoyi-ui/src/views/benyi/planweek/table.vue
@@ -0,0 +1,14 @@
+<template>
+  <div class="table-container"></div>
+</template>
+
+<script>
+export default {
+  name: 'PlayTable',
+  data() {
+    return {};
+  },
+  created() {},
+  methods: {},
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/benyi/thememonthplan/table.vue b/ruoyi-ui/src/views/benyi/thememonthplan/table.vue
new file mode 100644
index 000000000..b3189739e
--- /dev/null
+++ b/ruoyi-ui/src/views/benyi/thememonthplan/table.vue
@@ -0,0 +1,14 @@
+<template>
+  <div class="table-container"></div>
+</template>
+
+<script>
+export default {
+  name: 'MonthTable',
+  data() {
+    return {};
+  },
+  created() {},
+  methods: {},
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/benyi/themetermplan/table.vue b/ruoyi-ui/src/views/benyi/themetermplan/table.vue
new file mode 100644
index 000000000..7f81e1513
--- /dev/null
+++ b/ruoyi-ui/src/views/benyi/themetermplan/table.vue
@@ -0,0 +1,14 @@
+<template>
+  <div class="table-container"></div>
+</template>
+
+<script>
+export default {
+  name: 'TermTable',
+  data() {
+    return {};
+  },
+  created() {},
+  methods: {},
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/benyi/themeweekplan/table.vue b/ruoyi-ui/src/views/benyi/themeweekplan/table.vue
new file mode 100644
index 000000000..81070d26d
--- /dev/null
+++ b/ruoyi-ui/src/views/benyi/themeweekplan/table.vue
@@ -0,0 +1,196 @@
+<template>
+  <div class="table-container" ref="printMe">
+    <h2 class="title">主题整合课程周教学计划表</h2>
+    <div class="table">
+      <div class="print no-print">
+        <el-button type="primary" plain size="mini" icon="el-icon-printer" @click="prints"></el-button>
+      </div>
+      <table>
+        <tr class="align-center">
+          <td v-for="h in headerData" :key="h.title">
+            <b class="table-title">{{h.title}}</b>
+            {{h.name}}
+          </td>
+        </tr>
+        <tr class="align-center table-bg">
+          <td v-for="h in bodyData.title" :key="h.prop">
+            <b>{{h.label}}</b>
+          </td>
+        </tr>
+        <tr v-for="item in bodyData.data" :key="item.day">
+          <td v-if="item.theme" :rowspan="item.rowspan" class="align-center">
+            <span>{{item.theme}}</span>
+          </td>
+          <td class="align-center">{{item.day}}</td>
+          <td>{{item.name}}</td>
+          <td class="align-center">{{item.term}}</td>
+          <td v-if="item.help" :rowspan="item.rowspan">{{item.help}}</td>
+        </tr>
+        <tr>
+          <td class="align-center">备注</td>
+          <td colspan="4"></td>
+        </tr>
+        <tr>
+          <td class="align-center">主管审批</td>
+          <td colspan="4"></td>
+        </tr>
+      </table>
+      <p
+        class="warning"
+      >注:此周计划表不需要发给家长,只需上报教学主管。制定班级一周教学与活动计划表,请使用班级管理模块中“教学与游戏活动周计划表”,以上报教学主管和作为周计划通知发给家长。</p>
+    </div>
+  </div>
+</template>
+
+<script>
+
+export default {
+  name: "WeekTable",
+  data() {
+    return {
+      tableData: [],
+      headerData: [
+        {
+          title: "班级:",
+          name: "多多班",
+        },
+        {
+          title: "月份:",
+          name: "3月份",
+        },
+        {
+          title: "周次:",
+          name: "多多班",
+        },
+        {
+          title: "月主题:",
+          name: "多多班",
+        },
+        {
+          title: "制表人:",
+          name: "多多班",
+        },
+      ],
+      bodyData: {
+        title: [
+          {
+            label: "分主题",
+            prop: "theme",
+          },
+          {
+            label: "天",
+            prop: "day",
+          },
+          {
+            label: "活动名称",
+            prop: "name",
+          },
+          {
+            label: "分组性质",
+            prop: "term",
+          },
+          {
+            label: "家长支持",
+            prop: "help",
+          },
+        ],
+        data: [
+          {
+            theme: "春天的颜色",
+            day: "周一",
+            name: "活动",
+            term: "同质",
+            help: "1,sdfsdf,2sdfsd,3问问",
+            rowspan: 5,
+          },
+          {
+            day: "周二",
+            name: "活动",
+            term: "同质",
+          },
+          {
+            day: "周三",
+            name: "活动",
+            term: "同质",
+          },
+          {
+            day: "周四",
+            name: "活动",
+            term: "同质",
+          },
+          {
+            day: "周五",
+            name: "活动",
+            term: "同质",
+          },
+        ],
+      },
+    };
+  },
+  created() {},
+  methods: {
+    prints () {
+      this.$print(this.$refs.printMe);
+    }
+  },
+};
+</script>
+<style lang="scss">
+.table-container {
+  padding: 30px 10%;
+  .title {
+    margin: 0;
+    font-size: 18px;
+    text-align: center;
+    padding: 15px 0;
+  }
+  .align-center {
+    text-align: center;
+  }
+  .table {
+    font-size: 14px;
+    .print {
+      display: flex;
+      justify-content: flex-end;
+      padding-bottom: 10px;
+    }
+    p {
+      margin: 0;
+    }
+    table {
+      width: 100%;
+      border-collapse: collapse;
+    }
+    table td {
+      border: #ccc solid 1px;
+      line-height: 24px;
+      padding: 8px 5px;
+    }
+    .table-title {
+      font-size: 16px;
+    }
+    .table-bg {
+      background: #f8f8f8;
+    }
+  }
+  .warning {
+    padding-top: 20px;
+    font-size: 12px;
+    color: #666;
+  }
+}
+@media print {
+  .table-container {
+    padding: 30px 0;
+  }
+  .print {
+    opacity: 0;
+  }
+}
+/*去除页眉页脚*/
+@page{
+  size:  auto;   /* auto is the initial value */
+  margin: 3mm;  /* this affects the margin in the printer settings */
+}
+
+</style>
\ No newline at end of file