diff --git a/assets/NJ_BookTable/scene/NJ_BookTable.fire b/assets/NJ_BookTable/scene/NJ_BookTable.fire
index cd88a311b6b2999dd1417c6d40ace09fb06abe34..554336bfd73f028168cd388b08edbc2d62fd2368 100644
--- a/assets/NJ_BookTable/scene/NJ_BookTable.fire
+++ b/assets/NJ_BookTable/scene/NJ_BookTable.fire
@@ -78,13 +78,13 @@
     "_active": true,
     "_components": [
       {
-        "__id__": 29
+        "__id__": 34
       },
       {
-        "__id__": 30
+        "__id__": 35
       },
       {
-        "__id__": 31
+        "__id__": 36
       }
     ],
     "_prefab": null,
@@ -245,16 +245,16 @@
         "__id__": 6
       },
       {
-        "__id__": 25
+        "__id__": 26
       }
     ],
     "_active": true,
     "_components": [
       {
-        "__id__": 27
+        "__id__": 32
       },
       {
-        "__id__": 28
+        "__id__": 33
       }
     ],
     "_prefab": null,
@@ -317,19 +317,19 @@
         "__id__": 7
       },
       {
-        "__id__": 12
+        "__id__": 13
       },
       {
-        "__id__": 16
+        "__id__": 17
       },
       {
-        "__id__": 20
+        "__id__": 21
       }
     ],
-    "_active": true,
+    "_active": false,
     "_components": [
       {
-        "__id__": 24
+        "__id__": 25
       }
     ],
     "_prefab": null,
@@ -399,6 +399,9 @@
       },
       {
         "__id__": 11
+      },
+      {
+        "__id__": 12
       }
     ],
     "_prefab": null,
@@ -603,6 +606,74 @@
     "_originalHeight": 0,
     "_id": "85UeamOldJ3LdQv6cbs3Hu"
   },
+  {
+    "__type__": "cc.Button",
+    "_name": "",
+    "_objFlags": 0,
+    "node": {
+      "__id__": 7
+    },
+    "_enabled": true,
+    "_normalMaterial": null,
+    "_grayMaterial": null,
+    "duration": 0.1,
+    "zoomScale": 1.2,
+    "clickEvents": [],
+    "_N$interactable": true,
+    "_N$enableAutoGrayEffect": false,
+    "_N$transition": 0,
+    "transition": 0,
+    "_N$normalColor": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_N$pressedColor": {
+      "__type__": "cc.Color",
+      "r": 211,
+      "g": 211,
+      "b": 211,
+      "a": 255
+    },
+    "pressedColor": {
+      "__type__": "cc.Color",
+      "r": 211,
+      "g": 211,
+      "b": 211,
+      "a": 255
+    },
+    "_N$hoverColor": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "hoverColor": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_N$disabledColor": {
+      "__type__": "cc.Color",
+      "r": 124,
+      "g": 124,
+      "b": 124,
+      "a": 255
+    },
+    "_N$normalSprite": null,
+    "_N$pressedSprite": null,
+    "pressedSprite": null,
+    "_N$hoverSprite": null,
+    "hoverSprite": null,
+    "_N$disabledSprite": null,
+    "_N$target": null,
+    "_id": "d04RQHZHxPybDpAuSOHyVz"
+  },
   {
     "__type__": "cc.Node",
     "_name": "kdh",
@@ -613,14 +684,14 @@
     "_children": [],
     "_active": true,
     "_components": [
-      {
-        "__id__": 13
-      },
       {
         "__id__": 14
       },
       {
         "__id__": 15
+      },
+      {
+        "__id__": 16
       }
     ],
     "_prefab": null,
@@ -676,7 +747,7 @@
     "_name": "",
     "_objFlags": 0,
     "node": {
-      "__id__": 12
+      "__id__": 13
     },
     "_enabled": true,
     "_materials": [
@@ -708,7 +779,7 @@
     "_name": "",
     "_objFlags": 0,
     "node": {
-      "__id__": 12
+      "__id__": 13
     },
     "_enabled": true,
     "alignMode": 1,
@@ -735,7 +806,7 @@
     "_name": "",
     "_objFlags": 0,
     "node": {
-      "__id__": 12
+      "__id__": 13
     },
     "_enabled": true,
     "_normalMaterial": null,
@@ -796,7 +867,7 @@
     "hoverSprite": null,
     "_N$disabledSprite": null,
     "_N$target": {
-      "__id__": 12
+      "__id__": 13
     },
     "_id": "3cl54y78pGh7GzyRwC6XUa"
   },
@@ -810,14 +881,14 @@
     "_children": [],
     "_active": true,
     "_components": [
-      {
-        "__id__": 17
-      },
       {
         "__id__": 18
       },
       {
         "__id__": 19
+      },
+      {
+        "__id__": 20
       }
     ],
     "_prefab": null,
@@ -873,7 +944,7 @@
     "_name": "",
     "_objFlags": 0,
     "node": {
-      "__id__": 16
+      "__id__": 17
     },
     "_enabled": true,
     "_materials": [
@@ -905,7 +976,7 @@
     "_name": "",
     "_objFlags": 0,
     "node": {
-      "__id__": 16
+      "__id__": 17
     },
     "_enabled": true,
     "alignMode": 1,
@@ -932,7 +1003,7 @@
     "_name": "",
     "_objFlags": 0,
     "node": {
-      "__id__": 16
+      "__id__": 17
     },
     "_enabled": true,
     "_normalMaterial": null,
@@ -993,7 +1064,7 @@
     "hoverSprite": null,
     "_N$disabledSprite": null,
     "_N$target": {
-      "__id__": 16
+      "__id__": 17
     },
     "_id": "6acK64wVhOAbLiZEmUtwWJ"
   },
@@ -1007,14 +1078,14 @@
     "_children": [],
     "_active": true,
     "_components": [
-      {
-        "__id__": 21
-      },
       {
         "__id__": 22
       },
       {
         "__id__": 23
+      },
+      {
+        "__id__": 24
       }
     ],
     "_prefab": null,
@@ -1070,7 +1141,7 @@
     "_name": "",
     "_objFlags": 0,
     "node": {
-      "__id__": 20
+      "__id__": 21
     },
     "_enabled": true,
     "_materials": [
@@ -1102,7 +1173,7 @@
     "_name": "",
     "_objFlags": 0,
     "node": {
-      "__id__": 20
+      "__id__": 21
     },
     "_enabled": true,
     "alignMode": 1,
@@ -1129,7 +1200,7 @@
     "_name": "",
     "_objFlags": 0,
     "node": {
-      "__id__": 20
+      "__id__": 21
     },
     "_enabled": true,
     "_normalMaterial": null,
@@ -1190,7 +1261,7 @@
     "hoverSprite": null,
     "_N$disabledSprite": null,
     "_N$target": {
-      "__id__": 20
+      "__id__": 21
     },
     "_id": "29RvRx27JGjoTI88DWu+TZ"
   },
@@ -1228,11 +1299,18 @@
     "_parent": {
       "__id__": 5
     },
-    "_children": [],
+    "_children": [
+      {
+        "__id__": 27
+      }
+    ],
     "_active": true,
     "_components": [
       {
-        "__id__": 26
+        "__id__": 30
+      },
+      {
+        "__id__": 31
       }
     ],
     "_prefab": null,
@@ -1259,7 +1337,7 @@
       "ctor": "Float64Array",
       "array": [
         -352.121,
-        0,
+        -22.620000000000005,
         0,
         0,
         0,
@@ -1283,12 +1361,134 @@
     "groupIndex": 0,
     "_id": "fcQ83I201BUYpiHw346tT3"
   },
+  {
+    "__type__": "cc.Node",
+    "_name": "img",
+    "_objFlags": 0,
+    "_parent": {
+      "__id__": 26
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 28
+      },
+      {
+        "__id__": 29
+      }
+    ],
+    "_prefab": null,
+    "_opacity": 255,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 450,
+      "height": 600
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_trs": {
+      "__type__": "TypedArray",
+      "ctor": "Float64Array",
+      "array": [
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        1,
+        1,
+        1,
+        1
+      ]
+    },
+    "_eulerAngles": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_skewX": 0,
+    "_skewY": 0,
+    "_is3DNode": false,
+    "_groupIndex": 0,
+    "groupIndex": 0,
+    "_id": "e5h0lC/1BGkJL1Gf3DHZYT"
+  },
+  {
+    "__type__": "cc.Sprite",
+    "_name": "",
+    "_objFlags": 0,
+    "node": {
+      "__id__": 27
+    },
+    "_enabled": true,
+    "_materials": [
+      {
+        "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
+      }
+    ],
+    "_srcBlendFactor": 770,
+    "_dstBlendFactor": 771,
+    "_spriteFrame": null,
+    "_type": 0,
+    "_sizeMode": 0,
+    "_fillType": 0,
+    "_fillCenter": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0
+    },
+    "_fillStart": 0,
+    "_fillRange": 0,
+    "_isTrimmedMode": true,
+    "_atlas": null,
+    "_id": "0eG74YtohBhZ1H/s1qWRry"
+  },
   {
     "__type__": "cc.Widget",
     "_name": "",
     "_objFlags": 0,
     "node": {
-      "__id__": 25
+      "__id__": 27
+    },
+    "_enabled": true,
+    "alignMode": 1,
+    "_target": null,
+    "_alignFlags": 4,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_verticalCenter": 0,
+    "_horizontalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 0,
+    "_originalHeight": 600,
+    "_id": "c2dWn0ot1HfKzkaAnWRszt"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "node": {
+      "__id__": 26
     },
     "_enabled": true,
     "alignMode": 1,
@@ -1296,8 +1496,8 @@
     "_alignFlags": 13,
     "_left": 62.87900000000002,
     "_right": 0,
-    "_top": 60,
-    "_bottom": 60,
+    "_top": 82.62000000000003,
+    "_bottom": 37.37999999999998,
     "_verticalCenter": 0,
     "_horizontalCenter": 0,
     "_isAbsLeft": true,
@@ -1310,6 +1510,74 @@
     "_originalHeight": 600,
     "_id": "f95qipqS9MPYtPkUAMbgiy"
   },
+  {
+    "__type__": "cc.Button",
+    "_name": "",
+    "_objFlags": 0,
+    "node": {
+      "__id__": 26
+    },
+    "_enabled": true,
+    "_normalMaterial": null,
+    "_grayMaterial": null,
+    "duration": 0.1,
+    "zoomScale": 1.2,
+    "clickEvents": [],
+    "_N$interactable": true,
+    "_N$enableAutoGrayEffect": false,
+    "_N$transition": 0,
+    "transition": 0,
+    "_N$normalColor": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_N$pressedColor": {
+      "__type__": "cc.Color",
+      "r": 211,
+      "g": 211,
+      "b": 211,
+      "a": 255
+    },
+    "pressedColor": {
+      "__type__": "cc.Color",
+      "r": 211,
+      "g": 211,
+      "b": 211,
+      "a": 255
+    },
+    "_N$hoverColor": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "hoverColor": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_N$disabledColor": {
+      "__type__": "cc.Color",
+      "r": 124,
+      "g": 124,
+      "b": 124,
+      "a": 255
+    },
+    "_N$normalSprite": null,
+    "_N$pressedSprite": null,
+    "pressedSprite": null,
+    "_N$hoverSprite": null,
+    "hoverSprite": null,
+    "_N$disabledSprite": null,
+    "_N$target": null,
+    "_id": "35Ie+Ps3JKGYyMtZ//QWPt"
+  },
   {
     "__type__": "cc.Sprite",
     "_name": "",
diff --git a/assets/NJ_BookTable/scene/NJ_BookTable.ts b/assets/NJ_BookTable/scene/NJ_BookTable.ts
index d8f78cbc22d7b6469263029a8fb0f131f905542b..2fa1642b7685cdc7d35cda90efd571fc931b8a26 100644
--- a/assets/NJ_BookTable/scene/NJ_BookTable.ts
+++ b/assets/NJ_BookTable/scene/NJ_BookTable.ts
@@ -1,4 +1,4 @@
-import { asyncDelay, onHomeworkFinish } from "../script/util";
+import { asyncDelay, playAudioByUrl, asyncGetSpriteFrimeByUrl, buttonOnClick } from "../script/util";
 import { MyCocosSceneComponent } from "../script/MyCocosSceneComponent";
 
 const { ccclass, property } = cc._decorator;
@@ -7,14 +7,12 @@ const { ccclass, property } = cc._decorator;
 export default class SceneComponent extends MyCocosSceneComponent {
 
     addPreloadImage() {
-        // TODO 根据自己的配置预加载图片资源
-        // this._imageResList.push({ url: this.data.pic_url });
-        // this._imageResList.push({ url: this.data.pic_url_2 });
+        this._imageResList.push({ url: this.data.bookImg });
     }
 
     addPreloadAudio() {
-        // TODO 根据自己的配置预加载音频资源
-        // this._audioResList.push({ url: this.data.audio_url });
+        this._audioResList.push({ url: this.data.questionTextAudio });
+        this._audioResList.push({ url: this.data.bookAudio });
     }
 
     addPreloadAnima() {
@@ -22,12 +20,59 @@ export default class SceneComponent extends MyCocosSceneComponent {
     }
 
     async onLoadEnd() {
-        // TODO 加载完成后的逻辑写在这里, 下面的代码仅供参考
+        await this.initView();
         this.initListener();
     }
 
+    async initView() {
+        const levelNode = cc.find(`Canvas/bg/L${this.data.choseLevel}`);
+        if(!levelNode) {
+            return;
+        }
+        levelNode.active = true;
+        cc.find(`box/title`, levelNode).getComponent(cc.Label).string = this.data.title;
+
+        try {
+            const bookImgFrame:any = await asyncGetSpriteFrimeByUrl(this.data.bookImg);
+            cc.find(`Canvas/bg/bookImg/img`).getComponent(cc.Sprite).spriteFrame = bookImgFrame;
+        } catch (error) {
+            console.error(error);
+        }
+    }
+    
+
     initListener() {
+        const bgButton = cc.find(`Canvas/bg/bookImg`);
+        bgButton.on('click', () => {
+            playAudioByUrl(this.data.bookAudio);
+        });
 
+        const levelNode = cc.find(`Canvas/bg/L${this.data.choseLevel}`);
+        if(!levelNode) {
+            return;
+        }
+        const levelButton = cc.find(`box`, levelNode);
+        levelButton.on('click', ()=>{
+            if (levelButton['cantClick']) {
+                return;
+            }
+            levelButton['cantClick'] = true;
+            // TODO 播放骨骼动画
+            playAudioByUrl(this.data.questionTextAudio, ()=>{
+                // TODO 更新骨骼动画状态
+                levelButton['cantClick'] = false;
+            });
+        })
+       
+        buttonOnClick(cc.find(`kdh`, levelNode), () => {
+            // TODO 跳转到看动画(第一个课件)
+        });
+        buttonOnClick(cc.find(`dgs`, levelNode), () => {
+            // TODO 跳转到读故事(第二个课件)
+        });
+        buttonOnClick(cc.find(`qpy`, levelNode), () => {
+            // TODO 跳转到趣配音(第三个课件)
+        });
     }
 
    
diff --git a/assets/NJ_BookTable/script/MyCocosSceneComponent.ts b/assets/NJ_BookTable/script/MyCocosSceneComponent.ts
index 293015c9cc8c5896304cf36ceedf9d20e1bfb687..99989df0598eaf011ba64ba33c5cea795b1fe5d6 100644
--- a/assets/NJ_BookTable/script/MyCocosSceneComponent.ts
+++ b/assets/NJ_BookTable/script/MyCocosSceneComponent.ts
@@ -87,7 +87,7 @@ export class MyCocosSceneComponent extends cc.Component {
 
   preload() {
     const preloadArr = this._imageResList.concat(this._audioResList).concat(this._animaResList);
-    cc.assetManager.loadAny(preloadArr, null, null, (err, data) => {
+    cc.assetManager.loadAny(preloadArr, null, null, async (err, data) => {
 
       if (window && window["air"]) {
         // window["air"].onCourseInScreen = (next) => {
@@ -95,7 +95,7 @@ export class MyCocosSceneComponent extends cc.Component {
         //   this.onLoadEnd();
         //   next();
         // };
-        this.onLoadEnd();
+        await this.onLoadEnd();
         window["air"].hideAirClassLoading();
       } else {
         this.onLoadEnd();
diff --git a/assets/NJ_BookTable/script/defaultData.ts b/assets/NJ_BookTable/script/defaultData.ts
index e9e9f26a059f43626bd856e7b6d18d4012190783..8611581a968833e2039f1b44c7527f69dabf64ae 100644
--- a/assets/NJ_BookTable/script/defaultData.ts
+++ b/assets/NJ_BookTable/script/defaultData.ts
@@ -1,6 +1,9 @@
 export const defaultData = {
-  "pic_url": "http://staging-teach.cdn.ireadabc.com/ed94332a503c31e0908bd4c6923a2665.png",
-  "pic_url_2": "http://staging-teach.cdn.ireadabc.com/5fb60317ade0195d35ad8034d5370a7f.png",
-  "text": "This is a test label.",
-  "audio_url": "http://staging-teach.cdn.ireadabc.com/f47f1d7b5c160fe1c59500d180346240.mp3"
+  "title": "猩猩有个苹果。\n他想要什么?",
+  "questionTextAudio": "http://staging-teach.cdn.ireadabc.com/69a71b1cfb979a5e0b32d72c21c55423_l.mp3",
+  "audioFileName": "胜利音效1.mp3",
+  "choseLevel": "1",
+  "bookImg": "http://staging-teach.cdn.ireadabc.com/601b7713313df8ee51c3533ed2e8e63d.png",
+  "bookAudio": "http://staging-teach.cdn.ireadabc.com/1c923d9ad42a500edceba37a985b49d5_l.mp3",
+  "bookAudioFileName": "占位音频.mp3"
 }
\ No newline at end of file
diff --git a/assets/NJ_BookTable/script/util.ts b/assets/NJ_BookTable/script/util.ts
index 4a88100ddb7a6dbe49273353f09738a50a998b10..14ecf156c4950f2c379253eca6b5a4beff4c0072 100644
--- a/assets/NJ_BookTable/script/util.ts
+++ b/assets/NJ_BookTable/script/util.ts
@@ -71,64 +71,64 @@ export function setSprNodeMaxLen(sprNode, maxW, maxH) {
 }
 
 export function localPosTolocalPos(baseNode, targetNode) {
-	const worldPos = targetNode.parent.convertToWorldSpaceAR(cc.v2(targetNode.x, targetNode.y));
-	const localPos = baseNode.parent.convertToNodeSpaceAR(cc.v2(worldPos.x, worldPos.y));
-	return localPos;
+  const worldPos = targetNode.parent.convertToWorldSpaceAR(cc.v2(targetNode.x, targetNode.y));
+  const localPos = baseNode.parent.convertToNodeSpaceAR(cc.v2(worldPos.x, worldPos.y));
+  return localPos;
 }
 
 export function worldPosToLocalPos(worldPos, baseNode) {
-	const localPos = baseNode.parent.convertToNodeSpaceAR(cc.v2(worldPos.x, worldPos.y));
-	return localPos;
+  const localPos = baseNode.parent.convertToNodeSpaceAR(cc.v2(worldPos.x, worldPos.y));
+  return localPos;
 }
 
 export function getScaleRateBy2Node(baseNode, targetNode, maxFlag = true) {
-	const worldRect1 = targetNode.getBoundingBoxToWorld();
-	const worldRect2 = baseNode.getBoundingBoxToWorld();
+  const worldRect1 = targetNode.getBoundingBoxToWorld();
+  const worldRect2 = baseNode.getBoundingBoxToWorld();
 
-	const sx = worldRect1.width / worldRect2.width;
-	const sy = worldRect1.height / worldRect2.height;
-	if (maxFlag) {
-		return Math.max(sx, sy);
-	} else {
-		return Math.min(sx, sy);
-	}
+  const sx = worldRect1.width / worldRect2.width;
+  const sy = worldRect1.height / worldRect2.height;
+  if (maxFlag) {
+    return Math.max(sx, sy);
+  } else {
+    return Math.min(sx, sy);
+  }
 }
 
-export function getDistance (start, end){
-    var pos = cc.v2(start.x - end.x, start.y - end.y);
-    var dis = Math.sqrt(pos.x*pos.x + pos.y*pos.y);
-    return dis;
+export function getDistance(start, end) {
+  var pos = cc.v2(start.x - end.x, start.y - end.y);
+  var dis = Math.sqrt(pos.x * pos.x + pos.y * pos.y);
+  return dis;
 }
 
-export function playAudioByUrl(audio_url, cb=null) {
-	if (audio_url) {
-		cc.assetManager.loadRemote(audio_url, (err, audioClip) => {
+export function playAudioByUrl(audio_url, cb = null) {
+  if (audio_url) {
+    cc.assetManager.loadRemote(audio_url, (err, audioClip) => {
       const audioId = cc.audioEngine.play(audioClip, false, 0.8);
       if (cb) {
         cc.audioEngine.setFinishCallback(audioId, () => {
           cb();
         });
       }
-		});
-	}
+    });
+  }
 }
 
 
-export function btnClickAnima(btn, time=0.15, rate=1.05) {
+export function btnClickAnima(btn, time = 0.15, rate = 1.05) {
   btn.tmpScale = btn.scale;
   btn.on(cc.Node.EventType.TOUCH_START, () => {
     cc.tween(btn)
-      .to(time / 2, {scale: btn.scale * rate})
+      .to(time / 2, { scale: btn.scale * rate })
       .start()
   })
   btn.on(cc.Node.EventType.TOUCH_CANCEL, () => {
     cc.tween(btn)
-      .to(time / 2, {scale: btn.tmpScale})
+      .to(time / 2, { scale: btn.tmpScale })
       .start()
   })
   btn.on(cc.Node.EventType.TOUCH_END, () => {
     cc.tween(btn)
-      .to(time / 2, {scale: btn.tmpScale})
+      .to(time / 2, { scale: btn.tmpScale })
       .start()
   })
 }
@@ -143,6 +143,19 @@ export function getSpriteFrimeByUrl(url, cb) {
   })
 }
 
+export function asyncGetSpriteFrimeByUrl(url) {
+  return new Promise((resolve, reject) => {
+    cc.loader.load({ url }, (err, img) => {
+      if(err){
+        reject(err);
+        return;
+      }
+      const spriteFrame = new cc.SpriteFrame(img);
+      resolve(spriteFrame);
+    })
+  });
+}
+
 export function getSprNode(resName) {
   const sf = cc.find('Canvas/res/img/' + resName).getComponent(cc.Sprite).spriteFrame;
   const node = new cc.Node();
@@ -179,7 +192,7 @@ export async function asyncDelay(time) {
     try {
       cc.tween(cc.find('Canvas'))
         .delay(time)
-        .call(()=>{
+        .call(() => {
           resolve(null);
         })
         .start();
@@ -191,69 +204,69 @@ export async function asyncDelay(time) {
 
 export async function asyncLoadDragonBoneAnime(node, { skeJsonData: { url: skeJsonDataUrl }, texJsonData: { url: texJsonDataUrl }, texPngData: { url: texPngDataUrl } }) {
 
-    if (!texPngDataUrl || !texJsonDataUrl || !texPngDataUrl
-        || texPngDataUrl == '' || texJsonDataUrl == '' || texPngDataUrl == '') {
-        return;
-    }
+  if (!texPngDataUrl || !texJsonDataUrl || !texPngDataUrl
+    || texPngDataUrl == '' || texJsonDataUrl == '' || texPngDataUrl == '') {
+    return;
+  }
 
-    return new Promise((resolve, reject) => {
-        if (node.animaNode) {
-            node.animaNode.removeFromParent();
+  return new Promise((resolve, reject) => {
+    if (node.animaNode) {
+      node.animaNode.removeFromParent();
+    }
+    const animaNode = new cc.Node();
+    animaNode.name = 'animaNode';
+    animaNode.parent = node;
+    animaNode.active = true;
+    node.animaNode = animaNode;
+
+    const dragonDisplay = animaNode.addComponent(dragonBones.ArmatureDisplay);
+
+    const loadTexture = new Promise((resolve, reject) => {
+      cc.assetManager.loadRemote(texPngDataUrl, (error, texture) => {
+        if (error) {
+          reject(error);
         }
-        const animaNode = new cc.Node();
-        animaNode.name = 'animaNode';
-        animaNode.parent = node;
-        animaNode.active = true;
-        node.animaNode = animaNode;
-
-        const dragonDisplay = animaNode.addComponent(dragonBones.ArmatureDisplay);
-
-        const loadTexture = new Promise((resolve, reject) => {
-            cc.assetManager.loadRemote(texPngDataUrl, (error, texture) => {
-                if (error) {
-                    reject(error);
-                }
-                resolve(texture);
-            });
-        });
+        resolve(texture);
+      });
+    });
 
-        const loadTexJsonData = new Promise((resolve, reject) => {
-            cc.assetManager.loadAny({ url: texJsonDataUrl }, (error, atlasJson) => {
-                if (error) {
-                    reject(error);
-                }
-                resolve(atlasJson);
-            });
-        });
+    const loadTexJsonData = new Promise((resolve, reject) => {
+      cc.assetManager.loadAny({ url: texJsonDataUrl }, (error, atlasJson) => {
+        if (error) {
+          reject(error);
+        }
+        resolve(atlasJson);
+      });
+    });
 
-        const loadSkeJsonData = new Promise((resolve, reject) => {
-            cc.assetManager.loadAny({ url: skeJsonDataUrl }, (error, dragonBonesJson) => {
-                if (error) {
-                    reject(error);
-                }
-                resolve(dragonBonesJson);
-            });
-        });
+    const loadSkeJsonData = new Promise((resolve, reject) => {
+      cc.assetManager.loadAny({ url: skeJsonDataUrl }, (error, dragonBonesJson) => {
+        if (error) {
+          reject(error);
+        }
+        resolve(dragonBonesJson);
+      });
+    });
 
-        Promise.all([loadTexture, loadTexJsonData, loadSkeJsonData]).then(([texture, atlasJson, dragonBonesJson]) => {
-            const atlas = new dragonBones.DragonBonesAtlasAsset();
-            atlas.atlasJson = JSON.stringify(atlasJson);
-            atlas.texture = texture;
+    Promise.all([loadTexture, loadTexJsonData, loadSkeJsonData]).then(([texture, atlasJson, dragonBonesJson]) => {
+      const atlas: any = new dragonBones.DragonBonesAtlasAsset();
+      atlas.atlasJson = JSON.stringify(atlasJson);
+      atlas.texture = texture;
 
-            const asset = new dragonBones.DragonBonesAsset();
-            asset.dragonBonesJson = JSON.stringify(dragonBonesJson);
+      const asset = new dragonBones.DragonBonesAsset();
+      asset.dragonBonesJson = JSON.stringify(dragonBonesJson);
 
-            dragonDisplay.dragonAtlasAsset = atlas;
-            dragonDisplay.dragonAsset = asset;
+      dragonDisplay.dragonAtlasAsset = atlas;
+      dragonDisplay.dragonAsset = asset;
 
-            let armatureNames = dragonBonesJson.armature.map(data => data.name);
+      let armatureNames = (<any>dragonBonesJson).armature.map(data => data.name);
 
-            if (armatureNames.length > 0) {
-                dragonDisplay.armatureName = armatureNames[0];
-            }
-            resolve(animaNode);
-        });
+      if (armatureNames.length > 0) {
+        dragonDisplay.armatureName = armatureNames[0];
+      }
+      resolve(animaNode);
     });
+  });
 }
 
 export class FireworkSettings {
@@ -411,56 +424,112 @@ export function showTrebleFirework(baseNode, rabbonList) {
   showFireworks(right);
 }
 
-export function httpHeadCall(requsetUrl: string, callback) {
-  let xhr = new XMLHttpRequest();
-  console.log("Status: Send Post Request to " + requsetUrl);
-  try {
-    xhr.onreadystatechange = () => {
-      try {
-        console.log('xhr.readyState: ', xhr.readyState);
-        if (xhr.readyState == 4) {
-          if ((xhr.status >= 200 && xhr.status < 400)) {
-            callback(true);
-          } else {
-            callback(false);
-          }
-        }
+export function onHomeworkFinish() {
+  const middleLayer = cc.find('middleLayer');
+  if (middleLayer) {
+    const middleLayerComponent = middleLayer.getComponent('middleLayer');
+    if (middleLayerComponent.role == 'student') {
+      middleLayerComponent.onHomeworkFinish(() => { });
+    }
+  } else {
+    console.log('onHomeworkFinish');
+  }
+}
 
-      } catch (e) {
-        console.log(e)
-      }
-    };
-    xhr.open("HEAD", requsetUrl, true);
-    xhr.send();
-    xhr.timeout = 15000;
-    xhr.onerror = (e) => {
-      callback(false);
-    };
-    xhr.ontimeout = (e) => {
-      callback(false);
-    };
-  } catch (e) {
-    console.log("Send Get Request error: ", e);
+export function asyncCallNetworkApiGet(apiName, data): Promise<any> {
+  return new Promise((resolve, reject) => {
+    callNetworkApiGet(apiName, data, (res => {
+      resolve(res);
+    }));
+  });
+}
+export function asyncCallNetworkApiPost(uri, data): Promise<any> {
+  return new Promise((resolve, reject) => {
+    callNetworkApiPost(uri, data, (res) => {
+      resolve(res);
+    });
+  });
+}
+
+export function callNetworkApiPost(uri, data, callBack) {
+  const middleLayer = cc.find('middleLayer')?.getComponent('middleLayer');
+  if (middleLayer) {
+    middleLayer.callNetworkApiPost(uri, data, callBack);
+    return;
   }
+  const baseUrl = 'http://staging-openapi.iteachabc.com';
+  const xhr = new XMLHttpRequest();
+  const url = `${baseUrl}${uri}`;
+  xhr.open("POST", url, true);
+  xhr.setRequestHeader('content-type', 'application/json');
+  xhr.onreadystatechange = () => {
+    if (xhr.readyState == 4) {
+      callBack(JSON.parse(xhr.responseText));
+    }
+  }
+  xhr.send(JSON.stringify(data));
 }
 
-export function onHomeworkFinish(data = "", callback = ()=>{}) {
+export function callNetworkApiGet(uri, data, callBack) {
+  const middleLayer = cc.find('middleLayer')?.getComponent('middleLayer');
+  if (middleLayer) {
+    middleLayer.callNetworkApiGet(uri, data, callBack);
+    return;
+  }
+  const baseUrl = 'http://staging-openapi.iteachabc.com';
+  let queryStr = '?';
+  const params = [];
+  for (const key in data) {
+    if (Object.hasOwnProperty.call(data, key)) {
+      params.push(`${key}=${data[key]}`);
+    }
+  }
+  queryStr += params.join("&");
+  const xhr = new XMLHttpRequest();
+  xhr.onreadystatechange = () => {
+    if (xhr.readyState == 4 && (xhr.status >= 200 && xhr.status < 400)) {
+      callBack(xhr.responseText);
+    }
+  };
+  const url = `${baseUrl}${uri}${queryStr}`;
+  console.log('url = ' + url);
+  xhr.open('GET', url, true);
+  xhr.send();
+}
+
+export function jumpToBundle(bundleName: string) {
   const middleLayer = cc.find('middleLayer');
   if (middleLayer) {
     const middleLayerComponent = middleLayer.getComponent('middleLayer');
-    middleLayerComponent.onHomeworkFinish(callback, data);
+    middleLayerComponent.loadOnlineBundle(bundleName);
   } else {
-    console.log('onHomeworkFinish', JSON.stringify(data));
+    console.log('jump to bundle: ' + bundleName);
   }
 }
 
-export function callMiddleLayerFunction(apiName: string, data: any, callback: Function) {
+export function jumpToCourseWare(courseWareId: number) {
   const middleLayer = cc.find('middleLayer');
   if (middleLayer) {
     const middleLayerComponent = middleLayer.getComponent('middleLayer');
-    middleLayerComponent.callMiddleLayerFunction(apiName, data, callback);
+    middleLayerComponent.loadOnlineCourseWare(courseWareId);
   } else {
-    console.log('callMiddleLayerFunction: ' + apiName);
+    console.log('jump to CourseWare: ' + courseWareId);
   }
 }
 
+export function buttonOnClick(button: cc.Node, callback: Function, scale = 1.0) {
+  button.on('click', () => {
+    if (button['cantClick']) {
+      return;
+    }
+    button['cantClick'] = true;
+    cc.tween(button)
+      .to(0.1, { scale: scale * 1.1 })
+      .to(0.1, { scale: scale })
+      .call(() => {
+        button['cantClick'] = false;
+        callback && callback();
+      })
+      .start();
+  });
+}