Переглянути джерело

:fire: 全能双师行业版代码整理

zhanghe 6 роки тому
батько
коміт
b7f457ec31
70 змінених файлів з 2829 додано та 1418 видалено
  1. 12 0
      src/lib/css/swiper.min.css
  2. 13 0
      src/lib/js/swiper.min.js
  3. 1 6
      src/res/tpl/CLScene.tpl
  4. 1 3
      src/res/tpl/CourseScene.tpl
  5. 111 0
      src/res/tpl/DownloadCollection.tpl
  6. 0 107
      src/res/tpl/DownloadScene.tpl
  7. 8 20
      src/res/tpl/GlobalGoodDetail.tpl
  8. 0 34
      src/res/tpl/IndexScene.tpl
  9. 14 0
      src/res/tpl/RelatedPKGScene.tpl
  10. 8 0
      src/res/tpl/RenewAlertScene.tpl
  11. 1 1
      src/res/tpl/RepeatLoginScene.tpl
  12. 7 0
      src/res/tpl/ScanToPayScene.tpl
  13. 63 4
      src/res/tpl/TerminalScene.tpl
  14. 66 0
      src/res/tpl/WaterfallIndexScene.tpl
  15. 2 1
      src/res/values/api.json
  16. BIN
      src/stage/index/assets/img/DownloadCollection/background.jpg
  17. BIN
      src/stage/index/assets/img/DownloadScene/download.png
  18. BIN
      src/stage/index/assets/img/IndexScene/background.jpg
  19. BIN
      src/stage/index/assets/img/IndexScene/entrance_collection.png
  20. BIN
      src/stage/index/assets/img/IndexScene/entrance_download.png
  21. BIN
      src/stage/index/assets/img/IndexScene/entrance_periphery.png
  22. BIN
      src/stage/index/assets/img/IndexScene/entrance_resource.png
  23. BIN
      src/stage/index/assets/img/IndexScene/entrance_training.png
  24. BIN
      src/stage/index/assets/img/ScanToPayScene/background.png
  25. BIN
      src/stage/index/assets/img/ScanToPayScene/goods_selected.png
  26. BIN
      src/stage/index/assets/img/ScanToPayScene/qr_code.png
  27. BIN
      src/stage/index/assets/img/TerminalScene/background.jpg
  28. BIN
      src/stage/index/assets/img/TerminalScene/background.png
  29. BIN
      src/stage/index/assets/img/TerminalScene/icon_shopcart.png
  30. BIN
      src/stage/index/assets/img/TerminalScene/icon_terminal.png
  31. BIN
      src/stage/index/assets/img/TerminalScene/quit.png
  32. BIN
      src/stage/index/assets/img/WaterfallIndexScene/arrow_down.png
  33. BIN
      src/stage/index/assets/img/WaterfallIndexScene/background.png
  34. BIN
      src/stage/index/assets/img/WaterfallIndexScene/entrance_download.png
  35. BIN
      src/stage/index/assets/img/WaterfallIndexScene/entrance_support.png
  36. BIN
      src/stage/index/assets/img/WaterfallIndexScene/entrance_terminal.png
  37. BIN
      src/stage/index/assets/img/WaterfallIndexScene/entrance_training.png
  38. BIN
      src/stage/index/assets/img/WaterfallIndexScene/icon_sysconf.png
  39. BIN
      src/stage/index/assets/img/WaterfallIndexScene/icon_wifi.png
  40. BIN
      src/stage/index/assets/img/WaterfallIndexScene/logo.png
  41. BIN
      src/stage/index/assets/img/icon_close.png
  42. 2 1
      src/stage/index/index.html
  43. 6 2
      src/stage/index/index.less
  44. 34 50
      src/stage/index/scene/CLScene.js
  45. 62 79
      src/stage/index/scene/CourseScene.js
  46. 366 0
      src/stage/index/scene/DownloadCollectionScene.js
  47. 0 211
      src/stage/index/scene/DownloadManagerScene.js
  48. 7 79
      src/stage/index/scene/GlobalGoodDetailScene.js
  49. 0 177
      src/stage/index/scene/IndexScene.js
  50. 3 3
      src/stage/index/scene/LoginScene.js
  51. 102 0
      src/stage/index/scene/RelatedPKGScene.js
  52. 109 0
      src/stage/index/scene/RenewAlertScene.js
  53. 137 0
      src/stage/index/scene/ScanToPayScene.js
  54. 3 3
      src/stage/index/scene/SplashScene.js
  55. 100 31
      src/stage/index/scene/TerminalScene.js
  56. 404 0
      src/stage/index/scene/WaterFallIndexScene.js
  57. 1 43
      src/stage/index/style/CLScene.less
  58. 62 87
      src/stage/index/style/CourseScene.less
  59. 269 0
      src/stage/index/style/DownloadCollection.less
  60. 0 213
      src/stage/index/style/DownloadScene.less
  61. 49 64
      src/stage/index/style/GlobalGoodDetail.less
  62. 0 145
      src/stage/index/style/IndexScene.less
  63. 2 2
      src/stage/index/style/Mixins.less
  64. 84 0
      src/stage/index/style/RelatedPKGScene.less
  65. 86 0
      src/stage/index/style/RenewAlertScene.less
  66. 153 0
      src/stage/index/style/ScanToPayScene.less
  67. 212 32
      src/stage/index/style/TerminalScene.less
  68. 223 0
      src/stage/index/style/WaterfallIndexScene.less
  69. 33 3
      src/util/API/APIClient.js
  70. 13 17
      src/util/course.js

Різницю між файлами не показано, бо вона завелика
+ 12 - 0
src/lib/css/swiper.min.css


Різницю між файлами не показано, бо вона завелика
+ 13 - 0
src/lib/js/swiper.min.js


+ 1 - 6
src/res/tpl/CLScene.tpl

@@ -7,12 +7,7 @@
         </div>
     </div>
     <div id="cl-right-panel">
-        <div class="control-panel">
-            <div id="cl-shopping-cart-btn" class="shopping-cart-btn-frame" fe-role="Widget">
-                <img src="./assets/img/CLScene/icon_shopcart.png" />
-            </div>
-            <div class="cart-num"></div>
-        </div>
+        <div class="control-panel"></div>
         <div id="cl-right-content-scroll" fe-role="Scroll" fe-cfg="scroll_dir:v">
             <ul id="cl-right-content-list" class="scroll-list" >
             </ul>

+ 1 - 3
src/res/tpl/CourseScene.tpl

@@ -9,9 +9,7 @@
 			<div fe-role="Widget" id="course-tab-detail" class="nav-item detail"></div>
 			<div fe-role="Widget" id="course-tab-periphery" class="nav-item periphery"></div>
 			<div fe-role="Widget" id="course-tab-collect" class="nav-item collect"></div>
-			<div fe-role="Widget" id="course-tab-cart" class="nav-item cart">
-				<div class="cart-num" id="cart-num"></div>
-			</div>
+			<div fe-role="Widget" id="course-tab-cart" class="nav-item cart"></div>
 		</div>
 	</div>
 	<div class="main" id="course-main"></div>

+ 111 - 0
src/res/tpl/DownloadCollection.tpl

@@ -0,0 +1,111 @@
+<div id="DownloadCollectionScene" fe-role="Switch">
+	<div id="dc-left-panel">
+		<div id="dc-left-tab-scroll" fe-role="Scroll" fe-cfg="scroll_dir:v">
+			<ul id="dc-left-tab-list" class="scroll-list">
+				<li id="download" class="tag-item" fe-role="Widget">
+					<span>本地下载</span>
+				</li>
+				<li id="collection" class="tag-item" fe-role="Widget">
+					<span>课程收藏</span>
+				</li>
+			</ul>
+		</div>
+	</div>
+	<div id="dc-right-panel">
+		<div id="download-background" class="download-bg-wrapper">
+			<div class="download-bg-header">
+		        <div class="header">
+					<div class="row row-header">
+						<div class="one right-border">下载日期</div>
+						<div class="two right-border">课程名称</div>
+						<div class="three right-border">课名称</div>
+						<div class="four right-border">容量</div>
+						<div class="five right-border">下载状态</div>
+						<div class="six">操作</div>
+					</div>
+		        </div>
+		        <div class="horizon-line first-line"></div>
+		        <div class="horizon-line"></div>
+		        <div class="horizon-line"></div>
+		        <div class="horizon-line"></div>
+		        <div class="horizon-line"></div>
+		        <div class="horizon-line"></div>
+		        <div class="horizon-line"></div>
+		        <div class="horizon-line"></div>
+		        <div class="horizon-line"></div>
+		  	</div>
+			<div class="back-row">
+				<div class="one"></div>
+				<div class="two"></div>
+				<div class="three"></div>
+				<div class="four"></div>
+				<div class="five"></div>
+				<div class="six"></div>
+			</div>
+			<div class="back-row">
+				<div class="one"></div>
+				<div class="two"></div>
+				<div class="three"></div>
+				<div class="four"></div>
+				<div class="five"></div>
+				<div class="six"></div>
+			</div>
+			<div class="back-row">
+				<div class="one"></div>
+				<div class="two"></div>
+				<div class="three"></div>
+				<div class="four"></div>
+				<div class="five"></div>
+				<div class="six"></div>
+			</div>
+			<div class="back-row">
+				<div class="one"></div>
+				<div class="two"></div>
+				<div class="three"></div>
+				<div class="four"></div>
+				<div class="five"></div>
+				<div class="six"></div>
+			</div>
+			<div class="back-row">
+				<div class="one"></div>
+				<div class="two"></div>
+				<div class="three"></div>
+				<div class="four"></div>
+				<div class="five"></div>
+				<div class="six"></div>
+			</div>
+			<div class="back-row">
+				<div class="one"></div>
+				<div class="two"></div>
+				<div class="three"></div>
+				<div class="four"></div>
+				<div class="five"></div>
+				<div class="six"></div>
+			</div>
+			<div class="back-row">
+				<div class="one"></div>
+				<div class="two"></div>
+				<div class="three"></div>
+				<div class="four"></div>
+				<div class="five"></div>
+				<div class="six"></div>
+			</div>
+			<div class="back-row">
+				<div class="one"></div>
+				<div class="two"></div>
+				<div class="three"></div>
+				<div class="four"></div>
+				<div class="five"></div>
+				<div class="six"></div>
+			</div>
+			<div class="back-row">
+				<div class="one"></div>
+				<div class="two"></div>
+				<div class="three"></div>
+				<div class="four"></div>
+				<div class="five"></div>
+				<div class="six"></div>
+			</div>
+		</div>
+	</div>
+</div>

+ 0 - 107
src/res/tpl/DownloadScene.tpl

@@ -1,107 +0,0 @@
-<div id="DownloadManagerScene" fe-role="Switch">
-	<div class="download-manager-bg">
-		<img src="./assets/img/GlobalGoodDetail/background.jpg" alt="" />
-	</div>
-  	<div class="local-download-icon">
-    	<img src="assets/img/DownloadScene/download.png" alt="" />
-    	<div>本地下载列表</div>
-  	</div>
-  	<div class="background-wrapper">
-		<div class="background-header">
-    		<div class="header">
-				<div class="row row-header">
-					<div class="one right-border">下载日期</div>
-					<div class="two right-border">课程名称</div>
-					<div class="three right-border">课名称</div>
-					<div class="four right-border">容量</div>
-					<div class="five right-border">下载状态</div>
-					<div class="six">操作</div>
-	    		</div>
-			</div>
-			<div class="horizon-line first-line"></div>
-			<div class="horizon-line"></div>
-			<div class="horizon-line"></div>
-			<div class="horizon-line"></div>
-			<div class="horizon-line"></div>
-			<div class="horizon-line"></div>
-			<div class="horizon-line"></div>
-			<div class="horizon-line"></div>
-			<div class="horizon-line"></div>
-    	</div>
-		<div class="back-row">
-			<div class="one"></div>
-			<div class="two"></div>
-			<div class="three"></div>
-			<div class="four"></div>
-			<div class="five"></div>
-			<div class="six"></div>
-    	</div>
-		<div class="back-row">
-			<div class="one"></div>
-			<div class="two"></div>
-			<div class="three"></div>
-			<div class="four"></div>
-			<div class="five"></div>
-			<div class="six"></div>
-	    </div>
-		<div class="back-row">
-			<div class="one"></div>
-			<div class="two"></div>
-			<div class="three"></div>
-			<div class="four"></div>
-			<div class="five"></div>
-			<div class="six"></div>
-	    </div>
-		<div class="back-row">
-			<div class="one"></div>
-			<div class="two"></div>
-			<div class="three"></div>
-			<div class="four"></div>
-			<div class="five"></div>
-			<div class="six"></div>
-		</div>
-		<div class="back-row">
-			<div class="one"></div>
-			<div class="two"></div>
-			<div class="three"></div>
-			<div class="four"></div>
-			<div class="five"></div>
-			<div class="six"></div>
-	  	</div>
-		<div class="back-row">
-			<div class="one"></div>
-			<div class="two"></div>
-			<div class="three"></div>
-			<div class="four"></div>
-			<div class="five"></div>
-			<div class="six"></div>
-    	</div>
-		<div class="back-row">
-			<div class="one"></div>
-			<div class="two"></div>
-			<div class="three"></div>
-			<div class="four"></div>
-			<div class="five"></div>
-			<div class="six"></div>
-    	</div>
-		<div class="back-row">
-			<div class="one"></div>
-			<div class="two"></div>
-			<div class="three"></div>
-			<div class="four"></div>
-			<div class="five"></div>
-			<div class="six"></div>
-	  	</div>
-		<div class="back-row">
-			<div class="one"></div>
-			<div class="two"></div>
-			<div class="three"></div>
-			<div class="four"></div>
-			<div class="five"></div>
-			<div class="six"></div>
-    	</div>
-    	<div fe-role="Scroll" fe-cfg="scroll_dir:v,scroll_center:con,scroll_duration:0.2,scroll_easing:linear" class="content-wrapper" >
-			<div class="scroll-list scroll-lines-wrapper clearfix" id="download-status-table-wrapper"></div>
-		</div>
-	</div>
-</div>

+ 8 - 20
src/res/tpl/GlobalGoodDetail.tpl

@@ -1,27 +1,18 @@
 <div id="GlobalGoodDetailScene" fe-role="Switch">
-    <div class="control-panel">
-        <!-- <div class="search-btn-frame" fe-role="Widget">
-            <img src="./assets/img/CLScene/search.png" />
-        </div> -->
-        <div class="shopping-cart-btn-frame" fe-role="Widget">
-            <img src="./assets/img/CLScene/shopping_cart.png" />
-        </div>
-        <div class="cart-num"></div>
-    </div>
     <div class="detail-panel">
         <div id="ggd-detail-cover" class="detail-cover"><div></div></div>
         <div class="detail-text-panel">
             <p id="ggd-detail-title" class="title">...</p>
             <p id="ggd-detail-price" class="price">¥...</p>
-            <p id="ggd-detail-desc" class="desc">...
-            </p>
-            <div class="detail-control-panel" id="detail-control-panel">
-                <!-- <div id="add-cart-btn" class="add-shop-cart-btn-frame" fe-role="Widget">
-                    <img src="./assets/img/GlobalGoodDetail/add_shop_cart.png" />
+            <p id="ggd-detail-desc" class="desc">...</p>
+        </div>
+        <div class="shopqr">
+            <div class="shopqr-wrapper">
+                <div class="shopqr-desc">
+                    <div class="shopqr-desc-big">微信扫描二维码</div>
+                    <div class="shopqr-desc-sub">进入微商城进行购买</div>
                 </div>
-                <div id="goto-course-btn" class="play-btn-frame" fe-role="Widget" >
-                    <img src="./assets/img/GlobalGoodDetail/play_course.png" />
-                </div> -->
+                <div id="ggd-detail-shopqr" class="shopqr-img"></div>
             </div>
         </div>
     </div>
@@ -29,9 +20,6 @@
         <p id="ggd-concerned-goods-count" class="concerned-goods-count"></p>
         <div id="ggd-concerned-goods-scroll" fe-role="Scroll" fe-cfg="scroll_dir:h, auto_list_width:yes">
             <ul id="ggd-concerned-goods-list" class="scroll-list" >
-                <!--<li class="item" fe-role="Widget">
-                    <img src="https://placeholdit.imgix.net/~text?txtsize=28&txt=Cover&w=114&h=114" />
-                </li>-->
             </ul>
         </div>
     </div>

+ 0 - 34
src/res/tpl/IndexScene.tpl

@@ -1,34 +0,0 @@
-<div id="IndexScene" fe-role="Switch">
-	<div class="index-bg"><img src="assets/img/IndexScene/background.jpg" alt=""></div>
- 	<div class="m-header-user" fe-role="Switch">
-		<div fe-role="Widget" class="user-info" id="user-info">
-			<div class="user-info-text">
-				<div id="terminal-name" class="terminal-name">未登陆, 请先点击这里</div>
-				<div id="terminal-id" class="terminal-id">再点击"退出账号"回到登陆页</div>
-			</div>
-		</div>
-	</div>
-	<!-- 首页底部的五个入口 -->
-	<div id="index-scroll" class="m-main" fe-role="Scroll" fe-cfg="scroll_dir:v,scroll_duration:0.2,scroll_easing:linear">
-		<div class="scroll-list">
-			<div id="history" class="history-wrapper"></div>
-			<div id="fun" class="fun-wrapper">
-				<div id="fun-download" class="fun-item" fe-role="Widget">
-					<img src="./../../stage/index/assets/img/IndexScene/entrance_download.png"/>
-				</div>
-				<div id="fun-collection" class="fun-item" fe-role="Widget">
-					<img src="./../../stage/index/assets/img/IndexScene/entrance_collection.png"/>
-				</div>
-				<div id="fun-resource" class="fun-item" fe-role="Widget">
-					<img src="./../../stage/index/assets/img/IndexScene/entrance_resource.png"/>
-				</div>
-				<div id="fun-periphery" class="fun-item" fe-role="Widget">
-					<img src="./../../stage/index/assets/img/IndexScene/entrance_periphery.png"/>
-				</div>
-				<div id="fun-training" class="fun-item" fe-role="Widget">
-					<img src="./../../stage/index/assets/img/IndexScene/entrance_training.png"/>
-				</div>
-			</div>
-		</div>
-	</div>
-</div>

+ 14 - 0
src/res/tpl/RelatedPKGScene.tpl

@@ -0,0 +1,14 @@
+<div id="RelatedPKGScene" fe-role="Switch">
+    <div class="related-pkg-bg">
+        <img src="assets/img/TerminalScene/background.png" alt="" />
+    </div>
+    <div class="icon-close" id="close-alert" fe-role="Widget">
+        <img src="assets/img/icon_close.png" alt="" />
+    </div>
+    <div class="related-pkg-wrapper">
+        <div class="course-name-wrapper"></div>
+        <div class="related-pkg" fe-role="Scroll" fe-cfg="scroll_dir:v,scroll_duration:0.2,scroll_easing:linear">
+            <div class="scroll-list related-pkg-scroll-list"></div>
+        </div>
+    </div>
+</div>

+ 8 - 0
src/res/tpl/RenewAlertScene.tpl

@@ -0,0 +1,8 @@
+<div id="RenewAlertScene" fe-role="Switch">
+    <div class="icon-close" id="close-alert" fe-role="Widget">
+        <img src="assets/img/icon_close.png" alt="" />
+    </div>
+    <div class="renew-product" fe-role="Scroll" fe-cfg="scroll_dir:v,scroll_duration:0.2,scroll_easing:linear">
+        <div class="scroll-list" id="renew-scroll-list"></div>
+    </div>
+</div>

+ 1 - 1
src/res/tpl/RepeatLoginScene.tpl

@@ -8,7 +8,7 @@
       <p>现在您不能使用。</p>
     </div>
     <div class="iknow" id="iknow-btn" fe-role="Widget">
-      <img src="./../../stage/index/assets/img/repeat_login_ikonw_btn.png" alt="">
+      <img src="./../../stage/index/assets/img/RepeatLoginScene/repeat_login_ikonw_btn.png" alt="">
     </div>
   </div>
 </div>

+ 7 - 0
src/res/tpl/ScanToPayScene.tpl

@@ -0,0 +1,7 @@
+<div id="ScanToPayScene" fe-role="Switch">
+    <div class="pay-bg">
+        <img src="assets/img/ScanToPayScene/background.png" alt="" />
+    </div>
+    <!-- 课程包价格列表及二维码 -->
+    <div class="pay-content"></div>
+</div>

+ 63 - 4
src/res/tpl/TerminalScene.tpl

@@ -1,7 +1,66 @@
 <div id="TerminalScene" fe-role="Switch">
-	<div class="terminal-bg">
-		<img src="assets/img/TerminalScene/background.jpg" alt="">
+	<div class="background">
+		<img src="assets/img/TerminalScene/background.png" alt="">
+	</div>
+	<div class="terminal">
+		<!-- id icon -->
+		<div class="semi-circle">
+			<img src="assets/img/TerminalScene/icon_terminal.png" alt="" />
+		</div>
+		<!-- 账号信息 -->
+		<ul class="info-content"></ul>
+		<!-- 退出账号 -->
+		<div class="quit-account" id="quit-account" fe-role="Widget">退出账号</div>
+	</div>
+	<div class="purchased">
+		<div class="title">
+			<div class="icon-shopcart">
+				<img src="assets/img/TerminalScene/icon_shopcart.png" alt="" />
+			</div>
+			<div class="text-description">购买记录</div>
+		</div>
+		<div class="back-table">
+			<div class="back-row table-header">
+				<div class="first-cell">&nbsp;&nbsp;课程包</div>
+				<div class="second-cell">购买日期</div>
+				<div class="third-cell">结束日期</div>
+			</div>
+			<!-- <div class="back-row">
+				<div class="first-cell"></div>
+				<div class="second-cell"></div>
+				<div class="third-cell"></div>
+			</div>
+			<div class="back-row">
+				<div class="first-cell"></div>
+				<div class="second-cell"></div>
+				<div class="third-cell"></div>
+			</div>
+			<div class="back-row">
+				<div class="first-cell"></div>
+				<div class="second-cell"></div>
+				<div class="third-cell"></div>
+			</div>
+			<div class="back-row">
+				<div class="first-cell"></div>
+				<div class="second-cell"></div>
+				<div class="third-cell"></div>
+			</div>
+			<div class="back-row">
+				<div class="first-cell"></div>
+				<div class="second-cell"></div>
+				<div class="third-cell"></div>
+			</div>
+			<div class="back-row">
+				<div class="first-cell"></div>
+				<div class="second-cell"></div>
+				<div class="third-cell"></div>
+			</div> -->
+		</div>
+		<div class="table-content clearfix" fe-role="Scroll" fe-cfg="scroll_dir:v,scroll_center:con,scroll_duration:0.2,scroll_easing:linear">
+			<div class="scroll-list" id="buy-record-list"></div>
+		</div>
+	</div>
+	<div class="back-message">
+		按遥控器<span>返回</span>键退出此界面
 	</div>
-	<ul fe-role="Switch" class="terminal-wrapper clearfix" id="terminal-wrapper"></ul>
-	<div class="terminal-quit" id="terminal-quit" fe-role="Widget" fe-cfg="default_focus:yes"></div>
 </div>

+ 66 - 0
src/res/tpl/WaterfallIndexScene.tpl

@@ -0,0 +1,66 @@
+<div id="WaterfallIndexScene" class="swiper-container-waterfall swiper-container" fe-role="Switch">
+  <!-- 首页背景图 -->
+  <div class="background">
+    <img src="assets/img/WaterfallIndexScene/background.png" alt="" />
+  </div>
+  <div id="waterfall-swiper" class="swiper-wrapper" fe-role="Scroll" fe-cfg="scroll_dir:v,scroll_duration:0.2,scroll_easing:linear">
+    <!-- slider-1: 首屏作为第一个silder -->
+    <div id="slide-0" class="swiper-slide">
+      <!-- 顶部工具条 -->
+      <div class="header">
+        <!-- 版本logo -->
+        <div class="logo">
+          <img src="assets/img/WaterfallIndexScene/logo.png" alt="" />
+        </div>
+        <!-- 系统设置icon -->
+        <div id="icon-system-config" class="system-config">
+          <img src="assets/img/WaterfallIndexScene/icon_sysconf.png" />
+        </div>
+        <!-- wifi网速 -->
+        <div id="icon-wifi" class="wifi">
+          <img src="assets/img/WaterfallIndexScene/icon_wifi.png" />
+        </div>
+        <!-- 时钟显示 -->
+        <div class="clock"></div>
+      </div>
+      <!-- 首页入口 -->
+      <div class="content">
+        <div class="scroll-list">
+          <!-- 左侧终端信息、收藏下载两个入口 -->
+          <div class="left">
+            <!-- 终端信息入口 -->
+            <div id="entrance-terminal" class="entrance" fe-role="Widget">
+              <img src="assets/img/WaterfallIndexScene/entrance_terminal.png" />
+            </div>
+            <!-- 收藏下载入口 -->
+            <div id="entrance-download" class="entrance" fe-role="Widget" fe-index="0" fe-goto="1;;;">
+              <img src="assets/img/WaterfallIndexScene/entrance_download.png" />
+            </div>
+          </div>
+          <!-- 中间轮播图 -->
+          <div id="advert-carousel" class="center"></div>
+          <!-- 右侧师训、配套入口 -->
+          <div class="right">
+            <!-- 师训入口 -->
+            <div id="entrance-training" class="entrance" fe-role="Widget">
+			    <img src="assets/img/WaterfallIndexScene/entrance_training.png"/>
+            </div>
+            <!-- 配套入口 -->
+            <div id="entrance-support" class="entrance" fe-role="Widget">
+			    <img src="assets/img/WaterfallIndexScene/entrance_support.png"/>
+            </div>
+          </div>
+          <!-- 首页推荐列表 -->
+          <div class="bottom" >
+            <div id="recommend" class="recommend-wrapper"></div>
+          </div>
+        </div>
+      </div>
+      <!-- 底部指示箭头 -->
+      <div class="arrow_down" style="display:none">
+        <img src="assets/img/WaterfallIndexScene/arrow_down.png" alt="" />
+      </div>
+    </div>
+  </div>
+  <div class="swiper-pagination swiper-pagination-waterfall"></div>
+</div>

+ 2 - 1
src/res/values/api.json

@@ -1,7 +1,8 @@
 {
     "api_url_kid": "http://kid-app.lingjiao.cn",
-    "api_url": "http://tt-web.api.ai160.com",
+    "api_url_test": "http://tt-web.api.ai160.com",
     "api_url_angelbell": "http://web-api.lingjiao.cn",
+    "api_url": "https://talenkid.lingjiao.cn",
     "api_url_light": "http://light-angelbell-web.lingjiao.cn",
     "api_url_inst": "http://lj-demo-web.ai160.com",
     "api_url_old_1": "http://2btv.efunbox.cn",

BIN
src/stage/index/assets/img/DownloadCollection/background.jpg


BIN
src/stage/index/assets/img/DownloadScene/download.png


BIN
src/stage/index/assets/img/IndexScene/background.jpg


BIN
src/stage/index/assets/img/IndexScene/entrance_collection.png


BIN
src/stage/index/assets/img/IndexScene/entrance_download.png


BIN
src/stage/index/assets/img/IndexScene/entrance_periphery.png


BIN
src/stage/index/assets/img/IndexScene/entrance_resource.png


BIN
src/stage/index/assets/img/IndexScene/entrance_training.png


BIN
src/stage/index/assets/img/ScanToPayScene/background.png


BIN
src/stage/index/assets/img/ScanToPayScene/goods_selected.png


BIN
src/stage/index/assets/img/ScanToPayScene/qr_code.png


BIN
src/stage/index/assets/img/TerminalScene/background.jpg


BIN
src/stage/index/assets/img/TerminalScene/background.png


BIN
src/stage/index/assets/img/TerminalScene/icon_shopcart.png


BIN
src/stage/index/assets/img/TerminalScene/icon_terminal.png


BIN
src/stage/index/assets/img/TerminalScene/quit.png


BIN
src/stage/index/assets/img/WaterfallIndexScene/arrow_down.png


BIN
src/stage/index/assets/img/WaterfallIndexScene/background.png


BIN
src/stage/index/assets/img/WaterfallIndexScene/entrance_download.png


BIN
src/stage/index/assets/img/WaterfallIndexScene/entrance_support.png


BIN
src/stage/index/assets/img/WaterfallIndexScene/entrance_terminal.png


BIN
src/stage/index/assets/img/WaterfallIndexScene/entrance_training.png


BIN
src/stage/index/assets/img/WaterfallIndexScene/icon_sysconf.png


BIN
src/stage/index/assets/img/WaterfallIndexScene/icon_wifi.png


BIN
src/stage/index/assets/img/WaterfallIndexScene/logo.png


BIN
src/stage/index/assets/img/icon_close.png


+ 2 - 1
src/stage/index/index.html

@@ -52,6 +52,7 @@
 	<script src="../../lib/js/blitz.js"></script>
 	<script src="../../lib/js/moye.min.js"></script>
 	<script src="../../lib/js/TVUtil.min.js"></script>
+	<script src="../../lib/js/swiper.min.js"></script>
 	<!-- <script src="https://cdn.ravenjs.com/3.23.2/raven.min.js"></script> -->
 	<!-- <script>
 		Raven.config('https://a9383032420e44af813de59554b62c24@sentry.io/304059').install();
@@ -65,7 +66,7 @@
 		document.head.appendChild(appCss);
 
 		var appScript = document.createElement('script');
-		appScript.src = './index.min.js?t=' + ts;
+		appScript.src = './index.js?t=' + ts;
 		document.body.appendChild(appScript);
 	</script>
 	<script>

+ 6 - 2
src/stage/index/index.less

@@ -11,16 +11,20 @@ body {
 
 /*@import '../../lib/css/marquee.css';*/
 @import '../../lib/css/keyPanel.css';
+@import '../../lib/css/swiper.min.css';
 @import './style/SplashScene.less';
 @import './style/LoginScene.less';
-@import './style/IndexScene.less';
+@import './style/WaterfallIndexScene.less';
 @import './style/TerminalScene.less';
-@import './style/DownloadScene.less';
+@import './style/DownloadCollection.less';
 @import './style/RepeatLoginScene.less';
+@import './style/RelatedPKGScene.less';
+@import './style/RenewAlertScene.less';
 @import './style/BuyConfirmScene.less';
 @import './style/DelConfirmScene.less';
 @import './style/QuitConfirmScene.less';
 @import './style/DataBuildingScene.less';
+@import './style/ScanToPayScene.less';
 @import './style/ShopCartScene.less';
 @import './style/ShopCartCheckScene.less';
 @import './style/CLScene.less';

+ 34 - 50
src/stage/index/scene/CLScene.js

@@ -1,9 +1,8 @@
-import APIClient from '../../../util/API/APIClient'
-import Consts from '../../../util/Consts'
-import CourseItem from '../../../component/CourseItem'
-import GoodsItem from '../../../component/GoodsItem'
-import ScrollEventPlugin from '../../../util/ScrollEventPlugin'
-import ShopCartState from '../../../util/ShopCartState';
+import APIClient from '../../../util/API/APIClient';
+import Consts from '../../../util/Consts';
+import CourseItem from '../../../component/CourseItem';
+import GoodsItem from '../../../component/GoodsItem';
+import ScrollEventPlugin from '../../../util/ScrollEventPlugin';
 import NotificationCenter from '../../../util/NotificationCenter';
 
 class CLScene extends scene {
@@ -46,37 +45,40 @@ class CLScene extends scene {
         document.getElementById('no-content-message').style.display = this.noContent ? '' : 'none';
 
         for (let i in dataset) {
-            const { id, title, subTitle, coverUrl, auth, goods } = dataset[i];
+            const { id, title, subTitle, coverUrl, auth, goods, redDot, openTime, closeTime, dateDesc } = dataset[i];
+
+            // 提取价格
             let price = '';
             if (goods && goods.length >= 1) {
-                price = goods[0].terminalPrice;
+              price = goods[0].terminalPrice;
             }
 
             let item = document.createElement('li');
             item.setAttribute('id', `item-${id}`);
+
             item.setAttribute('class', 'item');
             item.setAttribute('fe-role', 'Widget');
 
             if (0 == i) {
-                //第一个课程设为默认父组件的默认焦点子组件
-                item.setAttribute('fe-cfg', 'default_focus:yes');
+              //第一个课程设为默认父组件的默认焦点子组件
+              item.setAttribute('fe-cfg', 'default_focus:yes');
             }
 
             let itemDataset = {}
-            if (this.sceneType == 'periphery') {
-                itemDataset = {
-                    title,
-                    price,
-                    correlative: subTitle,
-                    img: Consts.IMG_PATH + '/' + coverUrl
-                }
+            if (this.sceneType == 'support') {
+              itemDataset = {
+                title,
+                price,
+                correlative: subTitle,
+                img: Consts.IMG_PATH + '/' + coverUrl
+              }
             } else {
-                itemDataset = {
-                    subject: title,
-                    subjectSub: subTitle,
-                    buyed: auth,
-                    img: Consts.IMG_PATH+ '/' + coverUrl
-                }
+              itemDataset = {
+                subject: title,
+                subjectSub: subTitle,
+                buyed: auth,
+                img: Consts.IMG_PATH+ '/' + coverUrl
+              }
             }
 
             item.innerHTML = component.createHTMLString(itemDataset);
@@ -93,7 +95,7 @@ class CLScene extends scene {
                 return;
             }
             this.selectedTagId = id;
-            if (this.sceneType == 'periphery') {
+            if (this.sceneType == 'support') {
                 this.loadPeripheryList(this.selectedTagId, 1);
             } else if (this.sceneType == 'collection') {
                 this.loadCollectionList(this.selectedTagId, 1);
@@ -107,7 +109,7 @@ class CLScene extends scene {
         this.rightScrollEvent.onScrollToBottom(() => {
             if (!this.hasNextPage) { return; }//如果没有下一页了,则不继续下面的程序
 
-            if (this.sceneType == 'periphery') {
+            if (this.sceneType == 'support') {
                 this.loadPeripheryList(this.selectedTagId, this.currentIndex + 1);
             } else if (this.sceneType == 'collection') {
                 this.loadCollectionList(this.selectedTagId, this.currentIndex + 1);
@@ -159,7 +161,7 @@ class CLScene extends scene {
 
     loadTagList() {
         let type = {
-            periphery: 'PERIPHERY',
+            support: 'PERIPHERY',
             resource: 'RESOURCE',
             training: 'TRAINING',
         }[this.sceneType] || 'DEFAULT';
@@ -183,7 +185,7 @@ class CLScene extends scene {
             }
             this.renderLeftTagList(res.data.list);
             this.selectedTagId = res.data.list[0].id;
-            if (this.sceneType == 'periphery') {
+            if (this.sceneType == 'support') {
                 this.loadPeripheryList(this.selectedTagId, 1);
             } else if (this.sceneType == 'collection') {
                 this.loadCollectionList(this.selectedTagId, 1);
@@ -207,13 +209,12 @@ class CLScene extends scene {
             this.initLeftTabOnFocus();
 
             this.rightScrollEvent.bind(this.moye.root.getWidgetById('cl-right-content-scroll'));
-            ShopCartState.getCount();
 
             NotificationCenter.add('collection_refresh', this.collectionObserver.bind(this));
         });
     }
 
-    onResume(data) {
+    onResume() {
 
     }
 
@@ -232,25 +233,20 @@ class CLScene extends scene {
     onInactive() {
 
     }
+
     // 所有事件类函数默认触发时会传递过来一个Event,其中包含着事件响应节点以及其他相关信息
     // 查看信息:console.log(e)
     // 获取Event节点Id的方法(前提是触发事件的节点存在Id)
     // 在使用Atv时Id对应:e.target.id
     // 非使用Atv是Id对应:e.target.id
     onOK(e) {
-        // 进入购物车场景
-        if (e.target.con.classList.contains('shopping-cart-btn-frame')) {
-            this.showScene(require('./ShopCartScene.js'), {});
-            return;
-        }
-
         let params = e.target.id.split('-');
         let prefix = params[0];
         let id = params[1];
 
         if (prefix != 'item') { return; }
         // 进入配套详情场景
-        if (this.sceneType == 'periphery') {
+        if (this.sceneType == 'support') {
             this.showScene(require('./GlobalGoodDetailScene.js'), { id });
             return;
         }
@@ -258,23 +254,11 @@ class CLScene extends scene {
         this.showScene(require(`./CourseScene.js`), { id });
     }
 
-    onBack(e) {
+    onBack() {
 
     }
 
     onKeydown(e) {
-        if (e.keyCode == Consts.KEYCODE_LEFT && e.target.id == 'cl-shopping-cart-btn') {
-            //无内容,直接返回
-            if (this.noContent) {
-              return;
-            }
-            //有内容,禁用向左按钮
-            e.preventDefault();
-            e.stopPropagation();
-            //单独的Widget不能阻止焦点变换,只能强行重新获取焦点来实现禁用向左
-            FocusEngine.getWidgetById('cl-shopping-cart-btn').focus();
-        }
-
         if(e.keyCode == Consts.KEYCODE_RIGHT && e.target.con.classList.contains('item')){
             if(this.noContent){
               return;
@@ -284,7 +268,7 @@ class CLScene extends scene {
         }
     }
 
-    onKeyup(e) {
+    onKeyup() {
 
     }
 }

+ 62 - 79
src/stage/index/scene/CourseScene.js

@@ -38,7 +38,6 @@ class CourseScene extends scene {
 				TVUtil.Toast.show('添加到购物车失败!', 1500);
 				return;
 			}
-			ShopCartState.updateCount();
 			this.loadDetail(this.id, focusButtonId);
 		});
 	}
@@ -74,20 +73,19 @@ class CourseScene extends scene {
 			let topBreadCrumb = document.getElementById('course-name');
 			let courseBG = document.getElementById('course-bg');
 			let collect = document.querySelector('#course-tab-collect');
-			// 1. set shopcart count
-			ShopCartState.getCount();
-			// 2. set backgroundImg
+
+			// 1. set backgroundImg
 			if (bgUrl) {
 				courseBG.setAttribute('src', `${Consts.IMG_PATH}/${bgUrl}`)
 			}
-			// 3. set breadCrumb
+			// 2. set breadCrumb
 			topBreadCrumb.innerHTML = breadCrumb;
 			this.title = title;
-			// 4. set collect state
+			// 3. set collect state
 			if (collected) {
 				collect.classList.add('selected');
 			}
-			// 5. render lesson list
+			// 4. render lesson list
 			Course.renderList(list, auth);
 			this.moye.root.reRender();
 			//光标放到第一节课, TODO:记录上次光标位置
@@ -95,7 +93,7 @@ class CourseScene extends scene {
 			if(firstLessonBtn){
 				firstLessonBtn.focus();
 			}
-			// 6. record course authority
+			// 5. record course authority
 			this.isBought = auth;
 		});
 	}
@@ -175,14 +173,34 @@ class CourseScene extends scene {
 				new Swiper(`slide-wrapper-${entity.id}`, discribePics, 3000, `${oneRem * 5.75}px`, `${oneRem * 5.75}px`);
 			}
 			this.moye.root.reRender();
-			// 刚进入光标定位到添加到购物车按钮
-			this.moye.root.getWidgetById('periphery-add-cart').focus();
+			// 记录当前光标指向的配套id
 			this.focusId = document.querySelector('.periphery-detail-wrapper').getAttribute('id').split('-')[3];
-			//change button status
-			if (entity.isInCart){
-				let addCartBtn = this.moye.root.getWidgetById('periphery-add-cart');
-				addCartBtn.con.classList.add('added');
-				addCartBtn.con.classList.remove('add-cart');
+		});
+	}
+
+	loadRelatedPackage(id, courseName) {
+		APIClient.getRelatedPackageList(id, (isTrue, res) => {
+			if (!isTrue) { return };
+			if (!res.success) {
+				TVUtil.Toast.show('相关课程包列表获取失败', 1500);
+				return;
+			}
+			// 未找到相关课程包给出提示
+			if (!res.data || !res.data.totalNum) {
+				TVUtil.Toast.show('未找到与该课程相关的课程包', 3000);
+			// 相关课程包有多个,跳转到选择场景
+			} else if (res.data.totalNum > 1) {
+				this.showScene(require('./RelatedPKGScene.js'), { courseName, relatedPkgs: res.data.recs });
+			// 相关课程包只有一个,直接跳转到支付界面
+			} else {
+				const pkg = res.data.recs[0];
+				const { id, name, recs, goods } = pkg;
+				this.showScene(require('./ScanToPayScene.js'), {
+					packageName: name,
+					courseList: recs,
+					packagePrices: goods,
+					courseNum: recs.length,
+				});
 			}
 		});
 	}
@@ -289,10 +307,7 @@ class CourseScene extends scene {
 		if (!data) { return }
 		if ('BuyConfirmScene' === data.backScene) {
 			if ('goBuy' === data.mode) {
-				//TODO:需降低耦合,统一管理路由,暂时先造个对象
-				this.navSwitch({ target: { id: 'course-tab-detail' } });
-				//将光标指向对应位置
-				this.moye.root.getWidgetById('course-tab-detail').focus();
+				this.loadRelatedPackage(this.id, this.title);
 				return;
 			} else {
 				return;
@@ -333,7 +348,7 @@ class CourseScene extends scene {
 
 	//获取SDCard 剩余存储空间
 	getAvailableBlocks(){
-  	let {status, data, error} = CommandBus.execute({type:CMD_TYPE.SD_CARD_USAGE, payload:{}})
+	  	let {status, data, error} = CommandBus.execute({type:CMD_TYPE.SD_CARD_USAGE, payload:{}})
 		if(!status && data && data.available > 0){
 			return data.available;
 		}
@@ -378,57 +393,30 @@ class CourseScene extends scene {
 			return;
 		}
 
-    	//购买课程
-		if (-1 !== e.target.id.indexOf('goods-')) {
-			if(e.target.con.classList.contains('added')) {
-				//不可用的Button
-				return;
-			}
-			const goodsId = e.target.id.split('-')[1];
-			this.addToCart(goodsId, e.target.id);
-			return;
-		}
+		//点击课的下载按钮
+		if (e.target.con.classList.contains('download-btn-lesson-list-ready')
+			|| e.target.con.classList.contains('download-btn-lesson-icon-ready')) {
+				let courseID = this.id;
+				let courseName = this.title;
 
-    //将课程中的配套加入购物车
-		if (e.target.con.classList.contains('add-cart') && e.target.con.dataset.goodsid) {
-			const peripheryGoodsId = e.target.con.dataset.goodsid;
-			APIClient.addToShopCart(peripheryGoodsId, (isTrue, res) => {
-				if (!isTrue) { return; }
-				if (!res.success) {
-					TVUtil.Toast.show('添加到购物车失败!', 1500);
+				let lessonID = e.target.con.dataset.id;
+				let lessonName = e.target.con.dataset.name;
+
+				let lessonSeq = parseInt(e.target.con.dataset.seq);
+				if (!this.isAuthorized(lessonSeq)) {
+					TVUtil.Toast.show('购买后方可下载!', 3000);
 					return;
 				}
-				ShopCartState.updateCount();
-				this.loadPeripheryDetail(this.focusIndex);
-				TVUtil.Toast.show('商品已加入购物车,可前往购物车中查看', 2000);
-			});
-			return;
-		}
-
-    //点击课的下载按钮
-    if (e.target.con.classList.contains('download-btn-lesson-list-ready')
-		|| e.target.con.classList.contains('download-btn-lesson-icon-ready')) {
-			let courseID = this.id;
-			let courseName = this.title;
-
-			let lessonID = e.target.con.dataset.id;
-			let lessonName = e.target.con.dataset.name;
 
-			let lessonSeq = parseInt(e.target.con.dataset.seq);
-			if (!this.isAuthorized(lessonSeq)) {
-				TVUtil.Toast.show('购买后方可下载!', 3000);
-				return;
-			}
-
-			if (this.getAvailableBlocks() < 200*1024){
-				//剩余空间小于200M
-				TVUtil.Toast.show('存储空间不足! 请到下载管理界面删除不需要的课以释放存储空间!', 3000);
-				return;
-			}
+				if (this.getAvailableBlocks() < 200*1024){
+					//剩余空间小于200M
+					TVUtil.Toast.show('存储空间不足! 请到下载管理界面删除不需要的课以释放存储空间!', 3000);
+					return;
+				}
 
-			//get courseware via Lesson
-			console.error('DEBUG, download cmd begin');
-			APIClient.getWareList(lessonID, courseID, (isTrue, res) => {
+				//get courseware via Lesson
+				console.error('DEBUG, download cmd begin');
+				APIClient.getWareList(lessonID, courseID, (isTrue, res) => {
 				if (!isTrue) { return; }
 				if (!res.success) {
 					TVUtil.Toast.show('获取课件列表失败!', 1500);
@@ -440,16 +428,16 @@ class CourseScene extends scene {
 					return;
 				}
 
-	      if (this.addLessonDownloadTask({resData, courseID, courseName, lessonID, lessonName})){
+				if (this.addLessonDownloadTask({resData, courseID, courseName, lessonID, lessonName})){
 					//set download-btn to ongoing
 					if (e.target.con.classList.contains('download-btn-lesson-list-ready')) {
-	    			e.target.con.classList.add('download-btn-lesson-list-ongoing')
-	    			e.target.con.classList.remove('download-btn-lesson-list-ready')
+						e.target.con.classList.add('download-btn-lesson-list-ongoing')
+						e.target.con.classList.remove('download-btn-lesson-list-ready')
 					} else {
-	    			e.target.con.classList.add('download-btn-lesson-icon-ongoing')
-	    			e.target.con.classList.remove('download-btn-lesson-icon-ready')
+						e.target.con.classList.add('download-btn-lesson-icon-ongoing')
+						e.target.con.classList.remove('download-btn-lesson-icon-ready')
 					}
-	      }
+				}
 			});//APIClient Over
 		}
 	}
@@ -529,15 +517,10 @@ class CourseScene extends scene {
 				this.toggleFavorited(this.id);
 				break;
 			case 'course-tab-cart':
-				let cart = document.getElementById('ShopCartScene');
-				if (cart) {
-					this.hideScene({ id: 0 }, 'ShopCartScene');
-					return;
-				}
-				this.showScene(require('./ShopCartScene.js'), { id: 0 });
+				this.loadRelatedPackage(this.id, this.title);
 				break;
 			default:
-				return;
+				break;
 		}
 	}
 }

+ 366 - 0
src/stage/index/scene/DownloadCollectionScene.js

@@ -0,0 +1,366 @@
+import Consts from '../../../util/Consts';
+import Utils from '../../../util/Utils';
+import APIClient from '../../../util/API/APIClient';
+import CourseItem from '../../../component/CourseItem';
+import GoodsItem from '../../../component/GoodsItem';
+import ScrollEventPlugin from '../../../util/ScrollEventPlugin';
+import NotificationCenter from '../../../util/NotificationCenter';
+import {CommandBus, CMD_TYPE} from '../../../util/CommandBus';
+
+class DownloadCollectionScene extends scene {
+    constructor(scope) {
+        super(scope);
+        this.lessonIds = [];
+        this.lessonItems = {};
+        this.rightScrollEvent = new ScrollEventPlugin();
+        this.hasNextPage = false;
+        this.currentIndex = 1;
+        this.noContent = false;
+    }
+
+    /**
+    * @desc 为每一个标签绑定focus事件
+    */
+    initLeftTabOnFocus() {
+        let leftScroll = this.moye.root.getWidgetById('dc-left-tab-scroll');
+        leftScroll.on('focus', e => {
+            if (e.target.id == 'download') {
+                const currentDom = document.getElementById('download-content');
+                if (!currentDom) {
+                    this.renderRightDownloadContent();
+                }
+            } else if (e.target.id == 'collection') {
+                const currentDom = document.getElementById('dc-right-content-scroll');
+                if (!currentDom) {
+                    this.renderRightCollectionContent();
+                }
+            }
+        });
+    }
+
+    // ===================== 渲染下载列表逻辑 ======================
+    /**
+    * @desc 渲染出下载列表
+    */
+    renderRightDownloadContent() {
+        // 删除收藏列表节点
+        const courseWrapperNode = document.getElementById('dc-right-content-scroll');
+        if (courseWrapperNode) {
+            courseWrapperNode.parentNode.removeChild(courseWrapperNode);
+        }
+        // 显示下载列表背景
+        document.getElementById('download-background').setAttribute('style', 'visibility:visible');
+        // 重置收藏请求页码
+        this.currentIndex = 1;
+
+        /*
+        // 假数据,方便在网页调试
+        let recs = []
+        for(let i=1; i < 15; i++){
+            recs.push({
+                'date':'2017-09-01',
+                'courseName':'同步辅导语文一年级'+i,
+                'courseID':'course-'+i,
+                'lessonName':'悯农',
+                'lessonID':'lesson-'+i,
+                'downloadStatus':'下载完成',
+                'createTime':1505187194,
+                'storageUsage':150211,
+            });
+        }*/
+        // 调安卓获取已下载的文件列表
+        let {status, data, error} = CommandBus.execute({type:CMD_TYPE.DOWNLOAD_ALL_LESSON_STATUS_GET, payload:{}});
+        let recs = [];
+        if (!status && data && data.recs){
+            recs = data.recs;
+        }
+        // 记录已下载的课id,快速观看使用此id
+        this.lessonIds = [];
+        for(let idx in recs){
+            let item = recs[idx];
+            this.lessonIds.push(item['lessonID']);
+            // make a map of lessonID to courseID
+            this.lessonItems[item['lessonID']] = {
+                'lessonName':item['lessonName'],
+                'courseID':item['courseID'],
+            }
+        }
+        let downloadTableHtml = this.generateDownloadStatusTable({recs});
+        let wrapper = document.createElement('div');
+        wrapper.setAttribute('id', 'download-content');
+        wrapper.setAttribute('class', 'download-content-wrapper');
+        wrapper.setAttribute('fe-role', 'Scroll');
+        wrapper.setAttribute('fe-cfg', 'scroll_dir:v,scroll_center:con,scroll_duration:0.2,scroll_easing:linea');
+        wrapper.innerHTML = downloadTableHtml;
+        document.getElementById('dc-right-panel').appendChild(wrapper);
+        this.moye.root.reRender();
+    }
+
+    /**
+    * @desc 生成下载列表
+    */
+    generateDownloadStatusTable({recs}) {
+        let trAcc = '';
+        let count = 0;
+        for (let idx in recs){
+            let rec = recs[idx];
+            let feCfg = "";
+            if (0 == count){
+                feCfg = "default_focus:yes";
+            }
+            count += 1;
+
+            //downloadDate
+            let downloadDateStr = '2017-09-10';
+            if (rec.createTime){
+                let createDate = new Date();
+                createDate.setTime(rec.createTime);
+                downloadDateStr = Utils.dateFormat(createDate, 'yyyy-MM-dd');
+            }
+            let downloadStatus = rec['downloadStatus'];
+            let downloadDesc = '';
+
+            //storageUsage
+            let storageUsageStr = '';
+            if (rec.storageUsage){
+                storageUsageStr = '' + parseInt(rec.storageUsage/1000) + 'M';
+            }
+
+            //downloadStatus
+            switch (downloadStatus) {
+                case Consts.DOWNLOAD_STATUS_UNDOWNLOAD:
+                    downloadDesc = '未下载';
+                    break;
+                case Consts.DOWNLOAD_STATUS_ONGOING:
+                    // downloadDesc = '已下载'+rec['progress']*100 + '%';
+                    downloadDesc = '正在下载';
+                    break;
+                case Consts.DOWNLOAD_STATUS_SUCCESS:
+                    downloadDesc = '下载完成';
+                    break;
+                case Consts.DOWNLOAD_STATUS_FAILED:
+                    downloadDesc = '下载失败';
+                    break;
+                default:
+                    downloadDesc = '未下载';
+            }
+            if (!rec['lessonName'])
+            {
+                rec['lessonName'] = rec['courseName'];
+            }
+
+            trAcc += `<div id='lesson-download-record-${rec['lessonID']}' class="row" lesson_id="${rec['lessonID']}">
+                <div class="one">${downloadDateStr}</div>
+                <div class="two">${rec['courseName']}</div>
+                <div class="three">${rec['lessonName']}</div>
+                <div class="four">${storageUsageStr}</div>
+                <div class="five">${downloadDesc}</div>
+                <div class="six" >
+                  <div id="download-btn-wrapper" fe-fole="Switch">
+                    <img src="./assets/img/DownloadCollection/download_enter_btn.png" id="enter-btn-lesson-${rec['lessonID']}" class="download-enter-btn" fe-role="Widget" data-id="${rec['lessonID']}" />
+                    <img src="./assets/img/DownloadCollection/download_del_btn.png" id="del-btn-lesson-${rec['lessonID']}" class="download-del-btn" fe-role="Widget" data-id="${rec['lessonID']}" />
+                  </div>
+                </div>
+                </div>`
+        }
+        const scrollList = `<div class="scroll-list scroll-lines-wrapper clearfix" id="download-status-table-wrapper">${trAcc}</div>`
+        return scrollList;
+    }
+
+    /**
+    * @desc 下载列表删除操作
+    */
+    deleteDownloadItem(retData) {
+        //send delete cmd
+        let lessonID = retData.lessonID;
+        let {status, data} = CommandBus.execute({type:CMD_TYPE.DOWNLOAD_LESSON_DELETE, payload:{lessonID}});
+        //delete dom node
+
+        //if(0 == status){
+        let curNode = document.getElementById('lesson-download-record-'+lessonID);
+        curNode.parentNode.removeChild(curNode);
+        //}
+
+        this.moye.root.reRender();
+        //找兄弟结点
+        let findIdx = this.lessonIds.indexOf(lessonID);
+        if(-1 == findIdx){
+            return;
+        }
+        this.lessonIds.splice(findIdx, 1);
+        if(findIdx >= this.lessonIds.length){
+            findIdx = this.lessonIds.length - 1;
+        }
+        let nextFocusLessonId = null;
+        if(findIdx >= 0){
+            nextFocusLessonId = this.lessonIds[findIdx];
+        }
+        if(nextFocusLessonId){
+            this.moye.root.getWidgetById('del-btn-lesson-'+nextFocusLessonId).focus();
+        }
+    }
+
+    // ================= 收藏内容渲染逻辑 ==================
+    /**
+    * @desc 收藏内容渲染
+    */
+    renderRightCollectionContent() {
+        // 隐藏下载列表的背景
+        document.getElementById('download-background').setAttribute('style', 'visibility:hidden');
+        // 删除下载列表节点
+        const downloadWrapperNode = document.getElementById('download-content');
+        if (downloadWrapperNode) {
+            downloadWrapperNode.parentNode.removeChild(downloadWrapperNode);
+        }
+        // 创建课程列表容器节点并添加到dom中
+        let wrapper = document.createElement('div');
+        wrapper.setAttribute('id', 'dc-right-content-scroll');
+        wrapper.setAttribute('fe-role', 'Scroll');
+        wrapper.setAttribute('fe-cfg', 'scroll_dir:v');
+        const scrollList = `
+            <ul id="dc-right-content-list" class="scroll-list" ></ul>
+            <div id="no-content-message" style="display:none;">
+                无内容
+            </div>`;
+        wrapper.innerHTML = scrollList;
+        document.getElementById('dc-right-panel').appendChild(wrapper);
+        // 重新渲染
+        this.moye.root.reRender();
+        // 加载收藏课程
+        this.loadCollectionList(this.currentIndex);
+    }
+
+    /**
+    * @desc 加载收藏列表
+    */
+    loadCollectionList(index) {
+        //tagId='',返回全部的收藏
+        APIClient.getCollectionList('', index, (isTrue, res) => {
+            if (!isTrue) { return; }
+            if (!res.success) {
+                TVUtil.Toast.show('获取收藏列表失败!', 1500);
+                this.moye.root.reRender();
+                return;
+            }
+            const { pageNo, pageSize, totalSize, list } = res.data || {};
+            this.hasNextPage = pageNo * pageSize < totalSize ? true : false;
+            this.currentIndex = pageNo;
+            this.renderCollectionList(list, CourseItem, index > 1);
+            this.rightScrollEvent.releaseEventLock();
+        });
+    }
+
+    /**
+    * @desc 滚动加载下一页收藏列表
+    */
+    initRightScrollReachEndEvent() {
+      this.rightScrollEvent.onScrollToBottom(() => {
+          if (!this.hasNextPage) { return; }//如果没有下一页了,则不继续下面的程序
+          this.loadCollectionList(this.currentIndex + 1);
+      });
+    }
+
+    /**
+    * @desc 渲染右侧面板中的收藏课程列表
+    */
+    renderCollectionList(dataset, component, isAppend) {
+        let list = document.getElementById('dc-right-content-list');
+
+        if (!isAppend) {
+            list.style.top = '0px';
+            while (list.hasChildNodes()) {
+                list.removeChild(list.lastChild);
+            }
+            this.initRightScrollReachEndEvent();
+        }
+
+        this.noContent = !dataset || dataset.length < 1;
+        FocusEngine.getWidgetById('dc-right-content-scroll').disabled = this.noContent;
+        document.getElementById('no-content-message').style.display = this.noContent ? '' : 'none';
+
+        for (let i in dataset) {
+            let currentItem = dataset[i];
+            let item = document.createElement('li');
+            item.setAttribute('id', `item-${currentItem.id}`);
+            item.setAttribute('class', 'item');
+            item.setAttribute('fe-role', 'Widget');
+            if(0 == i){
+                //第一个课程设为默认父组件的默认焦点子组件
+                item.setAttribute('fe-cfg', 'default_focus:yes');
+            }
+            const itemDataset = {
+                subject: currentItem.title,
+                subjectSub: currentItem.subTitle,
+                buyed: false,
+                img: Consts.IMG_PATH + '/' + currentItem.coverUrl,
+            };
+            item.innerHTML = component.createHTMLString(itemDataset);
+            list.appendChild(item);
+        }
+        this.moye.root.reRender();
+    }
+
+    onCreate() {
+        this.setContentView(require('../../../res/tpl/DownloadCollection.tpl'), {}, 'DownloadCollectionScene', {}, () => {
+            //页面渲染完成异步回调
+            this.initLeftTabOnFocus();
+            this.renderRightDownloadContent();
+        });
+    }
+
+    onOK(e) {
+        // 点击删除
+        if(e.target.con.classList.contains('download-del-btn')){
+            let lessonID = e.target.con.dataset.id;
+            let title = this.lessonItems[lessonID].lessonName;
+            let parentScene = 'DownloadCollectionScene';
+            this.showScene(require('./DelConfirmScene.js'), { parentScene, lessonID, title });
+        // 点击快速观看
+        } else if (e.target.con.classList.contains('download-enter-btn')) {
+            let lessonID = e.target.con.dataset.id;
+            let courseID = this.lessonItems[lessonID].courseID;
+            let lessonName = this.lessonItems[lessonID].lessonName;
+            this.showScene(require('./LessonScene.js'), {id:lessonID, courseId:courseID, title:lessonName});
+        // 点击courseItem
+        } else if (e.target.con.classList.contains('item')) {
+            let params = e.target.id.split('-');
+            let id = params[1];
+            this.showScene(require(`./CourseScene.js`), { id });
+        }
+    }
+
+    onKeydown() {
+
+    }
+
+    onKeyup() {
+
+    }
+
+    onResume(retData) {
+        if (!retData) return;
+        this.deleteDownloadItem(retData);
+    }
+
+    onPause() {
+
+    }
+
+    onDestroy() {
+
+    }
+
+    onActive() {
+
+    }
+
+    onInactive() {
+
+    }
+
+    onBack() {
+
+    }
+}
+
+module.exports = DownloadCollectionScene;

+ 0 - 211
src/stage/index/scene/DownloadManagerScene.js

@@ -1,211 +0,0 @@
-import Consts from '../../../util/Consts';
-import Utils from '../../../util/Utils';
-import {CommandBus, CMD_TYPE} from '../../../util/CommandBus';
-
-class DownloadManagerScene extends scene {
-    constructor(scope) {
-        super(scope);
-        this.lessonIds = [];
-        this.lessonItems = {};
-    }
-
-    generateDownloadStatusTable({recs}) {
-        let trAcc = '';
-        let count = 0;
-        for (let idx in recs) {
-            let rec = recs[idx];
-            let feCfg = "";
-            if (0 == count){
-                feCfg = "default_focus:yes";
-            }
-            count += 1;
-            //for tmp
-
-            //downloadDate
-            let downloadDateStr = '2017-09-10';
-            if (rec.createTime) {
-                let createDate = new Date();
-                createDate.setTime(rec.createTime);
-                downloadDateStr = Utils.dateFormat(createDate, 'yyyy-MM-dd');
-            }
-            let downloadStatus = rec['downloadStatus'];
-            let downloadDesc = '';
-
-            //storageUsage
-            let storageUsageStr = '';
-            if (rec.storageUsage){
-                storageUsageStr = '' + parseInt(rec.storageUsage/1000) + 'M';
-            }
-
-            //downloadStatus
-            switch (downloadStatus) {
-            case Consts.DOWNLOAD_STATUS_UNDOWNLOAD:
-                downloadDesc = '未下载';
-                break;
-            case Consts.DOWNLOAD_STATUS_ONGOING:
-                //downloadDesc = '已下载'+rec['progress']*100 + '%';
-                downloadDesc = '正在下载';
-                break;
-            case Consts.DOWNLOAD_STATUS_SUCCESS:
-                downloadDesc = '下载完成';
-                break;
-            case Consts.DOWNLOAD_STATUS_FAILED:
-                downloadDesc = '下载失败';
-                break;
-            default:
-                downloadDesc = '未下载';
-            }
-            if (!rec['lessonName']) {
-                rec['lessonName'] = rec['courseName'];
-            }
-
-            trAcc += `<div id='lesson-download-record-${rec['lessonID']}' class="row" lesson_id="${rec['lessonID']}">
-            <div class="one">${downloadDateStr}</div>
-            <div class="two">${rec['courseName']}</div>
-            <div class="three">${rec['lessonName']}</div>
-            <div class="four">${storageUsageStr}</div>
-            <div class="five">${downloadDesc}</div>
-            <div class="six" >
-              <div id="download-btn-wrapper" fe-fole="Switch">
-                <div id="enter-btn-lesson-${rec['lessonID']}" class="download-enter-btn" fe-role="Widget" data-id="${rec['lessonID']}">
-                  <img src="./assets/img/DownloadScene/download_enter_btn.png" class="img-btn"/>
-                </div>
-                <div id="del-btn-lesson-${rec['lessonID']}" class="download-del-btn" fe-role="Widget" data-id="${rec['lessonID']}" >
-                  <img src="./assets/img/DownloadScene/download_del_btn.png" class="img-btn"/>
-                </div>
-              </div>
-            </div>
-            </div>`
-            //<div class="delete-btn"  fe-role="Widget" fe-cfg="${feCfg}"/>
-            //<img src="./assets/img/download_del_btn.png" />
-        }
-        let header = `<div class="row header">
-          <div class="one">下载日期</div>
-          <div class="two">课程名称</div>
-          <div class="three">课名称</div>
-          <div class="four">容量</div>
-          <div class="five">下载状态</div>
-          <div class="six">操作</div>
-          </div>`
-        return `${trAcc}`;
-    }
-
-    onCreate() {
-        /*
-          let recs = []
-          for(let i=1; i < 15; i++){
-            recs.push({
-              'date':'2017-09-01',
-              'courseName':'同步辅导语文一年级上'+i,
-              'courseID':'course-'+i,
-              'lessonName':'悯农',
-              'lessonID':'lesson-'+i,
-              'downloadStatus':'下载完成',
-              'createTime':1505187194,
-              'storageUsage':150211,
-            });
-          }
-          */
-        let {status, data, error} = CommandBus.execute({type:CMD_TYPE.DOWNLOAD_ALL_LESSON_STATUS_GET, payload:{}});
-        let recs = [];
-        if (!status && data && data.recs){
-            recs = data.recs;
-        }
-
-        this.lessonIds = [];
-        for(let idx in recs){
-            let item = recs[idx];
-            this.lessonIds.push(item['lessonID']);
-
-            // make a map of lessonID to courseID
-            this.lessonItems[item['lessonID']] = {
-                'lessonName':item['lessonName'],
-                'courseID':item['courseID'],
-            }
-        }
-
-        //TVUtil.Toast.show(JSON.stringify({status,data, error, recs}), 5000);
-        this.setContentView(require('../../../res/tpl/DownloadScene.tpl'), {}, 'DownloadManagerScene', {}, () => {
-            let downloadStatusTableHtml = this.generateDownloadStatusTable({recs});
-            let downloadStatusTableWrapper = document.getElementById('download-status-table-wrapper');
-            downloadStatusTableWrapper.innerHTML = downloadStatusTableHtml;
-            this.moye.root.reRender();
-        });
-    }
-
-    onResume(retData) {
-      if (!retData) return;
-      //send delete cmd
-      let lessonID = retData.lessonID;
-      let {status, data} = CommandBus.execute({type:CMD_TYPE.DOWNLOAD_LESSON_DELETE, payload:{lessonID}});
-      //delete dom node
-
-      //if(0 == status){
-      let curNode = document.getElementById('lesson-download-record-'+lessonID);
-      curNode.parentNode.removeChild(curNode);
-      //}
-
-      this.moye.root.reRender();
-      //找兄弟结点
-      let findIdx = this.lessonIds.indexOf(lessonID);
-      if(-1 == findIdx){
-          return;
-      }
-      this.lessonIds.splice(findIdx, 1);
-      if(findIdx >= this.lessonIds.length){
-          findIdx = this.lessonIds.length - 1;
-      }
-      let nextFocusLessonId = null;
-      if(findIdx >= 0){
-          nextFocusLessonId = this.lessonIds[findIdx];
-      }
-      if(nextFocusLessonId){
-        this.moye.root.getWidgetById('del-btn-lesson-'+nextFocusLessonId).focus();
-      }
-    }
-
-    onPause() {
-
-    }
-
-    onDestroy() {
-
-    }
-
-    onActive() {
-
-    }
-
-    onInactive() {
-
-    }
-
-    onOK(e) {
-        if(e.target.con.classList.contains('download-del-btn')){
-            let lessonID = e.target.con.dataset.id;
-            let title = this.lessonItems[lessonID].lessonName;
-            let parentScene = 'DownloadManagerScene';
-            this.showScene(require('./DelConfirmScene.js'), { parentScene, lessonID, title });
-        } else if (e.target.con.classList.contains('download-enter-btn')) {
-            let lessonID = e.target.con.dataset.id;
-            let courseID = this.lessonItems[lessonID].courseID;
-            let lessonName = this.lessonItems[lessonID].lessonName;
-            // enter relative lesson scene
-            this.showScene(require('./LessonScene.js'), {id:lessonID, courseId:courseID, title:lessonName});
-        }
-    }
-
-    onBack() {
-
-    }
-
-    onKeydown() {
-
-    }
-
-    onKeyup() {
-
-    }
-}
-
-module.exports = DownloadManagerScene;

+ 7 - 79
src/stage/index/scene/GlobalGoodDetailScene.js

@@ -27,7 +27,7 @@ class GlobalGoodDetailScene extends scene {
         document.getElementById('ggd-detail-title').innerHTML = title + ' ' + subTitle;
         document.getElementById('ggd-detail-price').textContent = '¥' + Utils.twoDecimal_f(terminalPrice);
         document.getElementById('ggd-detail-desc').innerHTML = detail;
-        // discribePicUrlArray
+        // 描述图片列表
         let discribePics = [];
         if (imgList) {
             imgList.forEach(function (element) {
@@ -38,29 +38,11 @@ class GlobalGoodDetailScene extends scene {
             document.getElementById('ggd-detail-cover').innerHTML = `<div></div>`;
             this.swiper = new Swiper(`ggd-detail-cover`, discribePics, 3000, `${oneRem * 5.75}px`, `${oneRem * 5.75}px`);
         }
-
-        let btnWrapper = document.getElementById('detail-control-panel');
-        let addCartHTML = `<div id="add-cart-btn" data-goodsId="${goodsItem.id}" class="add-shop-cart-btn-frame add-cart" fe-role="Widget"><img src="./assets/img/GlobalGoodDetail/add_shop_cart.png" /></div>`;
-        let addCartBoughtHTML = `<div id="add-cart-btn" class="add-shop-cart-btn-frame" fe-role="Widget"><img src="./assets/img/course/detail/periphery_added.png" /></div>`;
-
-        if (relatedCourses && relatedCourses.length) {
-            //可能会有多个相关的课程,这里只取第一个
-            const courseId = relatedCourses[0].id;
-            const gotoCourseHTML= `<div id="goto-course-btn" data-course_id="${courseId}" class="play-btn-frame" fe-role="Widget"><img src="./assets/img/GlobalGoodDetail/play_course.png" /></div>`;
-            btnWrapper.innerHTML = goodsItem.isInCart ? `${addCartBoughtHTML}${gotoCourseHTML}` : `${addCartHTML}${gotoCourseHTML}`;
-            this.moye.root.reRender();
-        } else {
-            btnWrapper.innerHTML = goodsItem.isInCart ? `${addCartBoughtHTML}` : `${addCartHTML}`;
-            this.moye.root.reRender();
-        }
-
-        // 光标处理
-        if (goodsItem.isInCart) {
-            let addCartBtn = FocusEngine.getWidgetById('add-cart-btn');
-            addCartBtn.con.classList.add('added');
-            addCartBtn.con.classList.remove('add-cart');
-            addCartBtn.con.children[0].src = goodsItem.isInCart ? './assets/img/course/detail/periphery_added.png' : './assets/img/GlobalGoodDetail/add_shop_cart.png';
-        }
+        // 购物二维码(第一个价格的shopQR)
+        const { shopQR } = goodsItem;
+        let shopQRHTML = shopQR ? `<img src="${Consts.IMG_PATH}/${shopQR}" alt="" />` : '';
+        document.getElementById('ggd-detail-shopqr').innerHTML = shopQRHTML;
+        this.moye.root.reRender();
     }
 
     renderRelatedSupports(dataset) {
@@ -75,7 +57,7 @@ class GlobalGoodDetailScene extends scene {
 
         function concernedGoodItem(item) {
             return `<li id="ggd-concerned-${item.id}" class="item" fe-role="Widget">
-                        <img src="${ Consts.IMG_PATH + '/' + item.coverUrl}" />
+                        <img src="${Consts.IMG_PATH}/${item.coverUrl}" />
                     </li>`;
         }
         //清空容器
@@ -87,19 +69,6 @@ class GlobalGoodDetailScene extends scene {
         }
         listDom.innerHTML = listHtml;
         this.moye.root.reRender();
-
-        FocusEngine.getWidgetById('add-cart-btn').focus();
-        // 光标的处理逻辑
-        // let addCartBtn = FocusEngine.getWidgetById('add-cart-btn');
-        // let gotoCourseBtn = document.getElementById('goto-course-btn');
-        // if (addCartBtn && !addCartBtn.disabled) {
-        //   addCartBtn.focus();
-        // } else if (gotoCourseBtn) {
-        //   let gotoCourseBtn = FocusEngine.getWidgetById('goto-course-btn');
-        //   gotoCourseBtn.focus();
-        // } else if (dataset.length > 0) {
-        //   FocusEngine.getWidgetById(`ggd-concerned-${dataset[0].id}`).focus();
-        // }
     }
 
     loadGood(id) {
@@ -158,50 +127,9 @@ class GlobalGoodDetailScene extends scene {
     onOK(e) {
         if (e.target.con.classList.contains('item')) {
             let targetId = e.target.id.split('-')[2];
-            // targetId = 6;
             this.loadGood(targetId);
             return;
         }
-
-        if (e.target.con.classList.contains('add-cart')) {
-            const goodsId = e.target.con.dataset.goodsid;
-            APIClient.addToShopCart(goodsId, (isTrue, res) => {
-                if (!isTrue) { return; }
-                if (!res.success) {
-                    TVUtil.Toast.show('添加到购物车失败!', 1500);
-                    this.moye.root.reRender();
-                    return;
-                }
-                TVUtil.Toast.show('商品已加入购物车,可前往购物车中查看', 2000);
-                this.loadGood(this.pid);
-                ShopCartState.updateCount();
-            })
-            return;
-        }
-
-        if (e.target.con.classList.contains('shopping-cart-btn-frame')) {
-          if (-1 !== this.moye.focusList.indexOf('ShopCartScene')) {
-            this.hideScene({}, 'ShopCartScene');
-          } else {
-            this.hideScene();
-            this.showScene(require('./ShopCartScene.js'), {});
-          }
-          return;
-        }
-
-        if (e.target.id == Consts.DOM_ID_GOTO_COURSE_BUTTON) {
-          //goto course
-          let courseId = e.target.con.dataset.course_id;
-          if (courseId) {
-            //如果已在moye stack中, 则直接显示已有的
-            let passData = { id: courseId };
-            if ( -1 !== this.moye.focusList.indexOf('CourseScene')){
-              this.hideScene(passData, 'CourseScene');
-            } else {
-              this.showScene(require('./CourseScene.js'), passData);
-            }
-          }
-        }
     }
 
     onBack(e) {

+ 0 - 177
src/stage/index/scene/IndexScene.js

@@ -1,177 +0,0 @@
-import CourseItem from '../../../component/CourseItem';
-import APIClient from '../../../util/API/APIClient';
-import userDataStorage from '../../../util/userDataStorage';
-import Consts from '../../../util/Consts';
-import Utils from '../../../util/Utils';
-import { CommandBus, CMD_TYPE } from '../../../util/CommandBus';
-
-class IndexScene extends scene {
-	constructor(scope) {
-		super(scope);
-		this.subjectList = [];
-		this.scrollLock = true;
-	}
-
-	loadUserInfo() {
-		//判断deviceCode是否存在,不存在跳登录页面
-		if (!localStorage.getItem('deviceCode')) {
-			if ( -1 != this.moye.focusList.indexOf('LoginScene')) {
-				this.hideScene({}, 'LoginScene');
-			} else {
-				this.showScene(require('./LoginScene.js'), {});
-			}
-			return;
-		}
-		//deviceCode存在,刷新token
-		APIClient.refreshTokenByDeviceCode((isTrue, res) => {
-			if (!isTrue) { return; }
-			if (res.success) {
-				userDataStorage.setData(res.data);
-
-				//必须获取Token后才可以正常调用以下接口
-				this.loadHistoryList();
-				this.loadTerminal();
-
-				//记录用户登录行为
-				let {status, data} = CommandBus.execute({
-					type: CMD_TYPE.APP_BHV_USER_LOGIN,
-					payload: {
-						"eid": userDataStorage.getData().eid,
-						"uid": userDataStorage.getData().uid.toString(),
-					},
-				});
-			} else {
-				if ( -1 != this.moye.focusList.indexOf('LoginScene')) {
-					this.hideScene({}, 'LoginScene');
-				} else {
-					this.showScene(require('./LoginScene.js'), {});
-				}
-			}
-		});
-	}
-
-	renderHistoryList(dataset) {
-		let list = document.getElementById('history');
-		list.innerHTML = '';
-		let listHtml = '';
-
-		let firstCourseItemId = null;
-		for (let i in dataset) {
-			const { id, title, subTitle, coverUrl } = dataset[i];
-			let subject = title;
-			let subjectSub = subTitle;
-			let img = Consts.IMG_PATH + '/' + coverUrl;
-
-			let itemDataset = { img, subject, subjectSub, buyed: false };
-			if (0 == i) {
-				firstCourseItemId = `history-item-${id}`;
-			}
-			listHtml += `<div class="history-item" fe-role="Widget" id="history-item-${id}">${CourseItem.createHTMLString(itemDataset)}</div>`;
-		}
-		list.innerHTML = listHtml;
-		this.moye.root.reRender();
-
-		//默认焦点设置
-		if(firstCourseItemId){
-			this.moye.root.getWidgetById(firstCourseItemId).focus();
-		}
-	}
-
-	loadHistoryList() {
-		APIClient.getRecommendList((isTrue, res) => {
-			if (!isTrue) { return; }
-			if (!res.success) {
-				TVUtil.Toast.show('获取推荐列表失败!', 1500);
-			}
-			if (res.data) {
-				this.renderHistoryList(res.data);
-			} else {
-				this.renderHistoryList([]);
-			}
-		});
-	}
-
-	loadTerminal() {
-		let userData = userDataStorage.getData();
-		let terminal_name = document.querySelector('#terminal-name');
-		let terminal_id = document.querySelector('#terminal-id');
-		terminal_name.innerHTML = userData.name;
-		terminal_id.innerHTML = 'ID:' + userData.eid.replace(/(\d{4})/g, '$1 ');
-	}
-
-	onCreate() {
-		this.setContentView(require('../../../res/tpl/IndexScene.tpl'), {
-			'title': '2B双师教学标准平台'
-		}, 'IndexScene', {}, () => {
-			setAndroidEvent('keydown', 40);
-			if (!localStorage.getItem('deviceCode')) {
-				localStorage.setItem('deviceCode', window.efunbox ? window.efunbox.getUuidForDevice() : Utils.getUuidForWeb());
-			}
-			this.loadUserInfo();
-		});
-	}
-
-	onResume(data) {
-		if (data && data.success) {
-			// 必须获取Token后才可以正常调用以下接口,应该加入判断是否从登录页面恢复的过滤
-			this.loadUserInfo();
-		}
-	}
-
-	onPause() {
-
-	}
-
-	onDestroy() {
-
-	}
-
-	onActive() {
-
-	}
-
-	onInactive() {
-
-	}
-
-	// 所有事件类函数默认触发时会传递过来一个Event,其中包含着事件响应节点以及其他相关信息
-	// 查看信息:console.log(e)
-	// 获取Event节点Id的方法(前提是触发事件的节点存在Id)
-	// 在使用Atv时Id对应:e.target.id
-	// 非使用Atv是Id对应:e.target.id
-	onOK(e) {
-		// 点击终端信息、推荐列表、底部五个入口的处理逻辑
-		if (e.target.con.classList.contains('fun-item')) {
-			let type = e.target.id.replace('fun-', '');
-			if (type == 'download') {
-				this.showScene(require('./DownloadManagerScene.js'), {});
-			} else {
-				this.showScene(require('./CLScene.js'), { type });
-			}
-		} else if (e.target.con.classList.contains('user-info')) {
-			this.showScene(require('./TerminalScene.js'), {});
-		} else if (e.target.con.classList.contains('history-item')) {
-			let id = e.target.id.split('-')[2];
-			this.showScene(require('./CourseScene.js'), { id });
-		}
-	}
-
-	onBack() {
-		this.showScene(require('./QuitConfirmScene.js'), {});
-		return true;
-	}
-
-	onKeydown(e) {
-		if(Consts.KEYCODE_UP == e.keyCode){
-			if(e.target.con.classList.contains('history-item')){
-				this.moye.root.getWidgetById('user-info').focus();
-			}
-		}
-	}
-
-	onKeyup() {
-
-	}
-}
-
-module.exports = IndexScene;

+ 3 - 3
src/stage/index/scene/LoginScene.js

@@ -27,10 +27,10 @@ class LoginScene extends scene {
 			}
 			if (res.success) {
 				userDataStorage.setData(res.data);
-				if ( -1 != this.moye.focusList.indexOf('IndexScene')){
-					this.hideScene({success: true}, 'IndexScene');
+				if ( -1 != this.moye.focusList.indexOf('WaterfallIndexScene')){
+					this.hideScene({success: true}, 'WaterfallIndexScene');
 				} else {
-      				this.showScene(require('./IndexScene.js'), {});
+      				this.showScene(require('./WaterfallIndexScene.js'), {});
 				}
 			} else if (Consts.API_CODE_ISBOUND == res.code) {
 				this.showScene(require('./RepeatLoginScene.js'), {});

+ 102 - 0
src/stage/index/scene/RelatedPKGScene.js

@@ -0,0 +1,102 @@
+class RelatedPKGScene extends scene {
+	constructor(scope) {
+		super(scope);
+		this.packageMaps = {};
+		this.firstPackageId = '';
+	}
+
+    renderRelatedPKGScrollList({ courseName, relatedPkgs }) {
+        if (!relatedPkgs) {
+            return;
+        }
+        const relatedPKGItemTemplate = (dataset, index) => {
+            const { name, id } = dataset;
+            if (index === 0) {
+                this.firstPackageId = `related-pkg-${id}`;
+            }
+            return `
+                <div id="related-pkg-${id}" class="related-pkg-item" fe-role="Widget">
+                    <span class="related-pkg-name">《${name}》</span>
+                </div>
+            `;
+        }
+        let pkgHTMLList = [];
+        relatedPkgs.forEach((relatedPkg, index) => {
+            pkgHTMLList.push(relatedPKGItemTemplate(relatedPkg, index));
+        });
+        // 注入到页面
+        let courseNameContainer = document.querySelector('.course-name-wrapper');
+        let pkgListContainer = document.querySelector('.related-pkg-scroll-list');
+        courseNameContainer.innerHTML = `以下课程包中都含有【<span class="course-name">${courseName || ''}</span>】课程,请你选择:`;
+        pkgListContainer.innerHTML = pkgHTMLList.join('');
+        // 重新render
+        this.moye.root.reRender();
+        // 光标默认指向第一个课程包
+        this.moye.root.getWidgetById(this.firstPackageId).focus();
+    }
+
+	onCreate(data) {
+		if (data) {
+			let { courseName, relatedPkgs } = data;
+			if (!relatedPkgs || !relatedPkgs.length) {
+				relatedPkgs = [];
+			}
+			relatedPkgs.forEach(pkg => {
+				const { id, name, totalNum, recs, goods } = pkg;
+				this.packageMaps[id] = {
+					packageName: name,
+					courseList: recs,
+					packagePrices: goods,
+					courseNum: recs.length,
+				};
+			});
+        }
+		this.setContentView(require('../../../res/tpl/RelatedPKGScene.tpl'), {}, 'RelatedPKGScene', {}, () => {
+            this.renderRelatedPKGScrollList(data);
+		});
+	}
+
+	onResume() {
+
+	}
+
+	onPause() {
+
+	}
+
+	onDestroy() {
+
+	}
+
+	onActive() {
+
+	}
+
+	onInactive() {
+
+	}
+
+	onBack() {
+
+	}
+
+	onOK(e) {
+        if (e.target.con.classList.contains('icon-close')) {
+            this.hideScene({});
+        } else if (e.target.con.classList.contains('related-pkg-item')) {
+    		const packageId = e.target.id.split('-')[2];
+    		const passData = this.packageMaps[packageId];
+    		this.showScene(require('./ScanToPayScene.js'), { ...passData });
+        }
+	}
+
+	onKeydown() {
+
+	}
+
+	onKeyup() {
+
+	}
+}
+
+module.exports = RelatedPKGScene;

+ 109 - 0
src/stage/index/scene/RenewAlertScene.js

@@ -0,0 +1,109 @@
+import Consts from '../../../util/Consts';
+
+class RenewAlertScene extends scene {
+    constructor(scope) {
+    	super(scope);
+    }
+
+    renderRenewProductScrollList({ recs }) {
+        if (!recs) { return; }
+        const renewItemTemplate = (dataset) => {
+        const { name, type, id, endTime } = dataset;
+        // 计算到期时间
+        let duration = '';
+        try {
+            let nowTime = Math.floor(new Date().getTime() / 1000);
+            let expireTime = parseInt(endTime);
+            duration = Math.floor((expireTime - nowTime) / (24*60*60)).toString();
+        } catch(error) {
+            console.log('date parse error:', error);
+        }
+        // 产品类型code => name
+        let typeName = '';
+        switch(type) {
+            case Consts.TYPE_COURSE:
+                typeName = '课程';
+                break;
+            case Consts.TYPE_SUPPORT:
+                typeName = '周边配套';
+                break;
+            case Consts.TYPE_PACKAGE:
+                typeName = '课程包';
+                break;
+            default:
+                break;
+        }
+        return
+            `
+            <div id="renew-item-${id}" class="renew-item">
+                <span class="renew-item-name">《${name}》</span>
+                <span class="renew-item-type">${typeName}</span>
+                <span class="renew-item-btn" id="renew-btn-${id}" fe-role="Widget">续订</span>
+                <span class="renew-item-expire">
+                    <span class="renew-item-expire-day">${duration}</span>天后到期
+                </span>
+            </div>
+            `;
+        }
+        let renewHTMLList = [];
+        recs.forEach(rec => {
+            renewHTMLList.push(renewItemTemplate(rec));
+        });
+        // 注入到页面
+        let renewListContainer = document.querySelector('#renew-scroll-list');
+        renewListContainer.innerHTML = renewHTMLList.join('');
+        // 重新render
+        this.moye.root.reRender();
+        // 光标默认指向关闭按钮
+        FocusEngine.getWidgetById('close-alert').focus();
+    }
+
+	onCreate(data) {
+		this.setContentView(require('../../../res/tpl/RenewAlertScene.tpl'), {}, 'RenewAlertScene', { isParentShow: true }, () => {
+      this.renderRenewProductScrollList(data);
+		});
+	}
+
+	onResume() {
+
+	}
+
+	onPause() {
+
+	}
+
+	onDestroy() {
+
+	}
+
+	onActive() {
+
+	}
+
+	onInactive() {
+
+	}
+
+	onBack() {
+
+	}
+
+	onOK(e) {
+        if (e.target.con.classList.contains('icon-close')) {
+            this.hideScene({}, 'WaterfallIndexScene');
+        } else if (e.target.con.classList.contains('renew-item-btn')) {
+            let productId = e.target.id.split('-')[2]; //获取产品id
+            this.showScene(require('./ScanToPayScene.js'), { id: productId });
+        }
+	}
+
+	onKeydown() {
+
+	}
+
+	onKeyup() {
+
+	}
+}
+
+module.exports = RenewAlertScene;

+ 137 - 0
src/stage/index/scene/ScanToPayScene.js

@@ -0,0 +1,137 @@
+import APIClient from '../../../util/API/APIClient';
+import Consts from '../../../util/Consts';
+
+class ScanToPayScene extends scene {
+	constructor(scope) {
+		super(scope);
+        this.goodsArr = [];
+	}
+
+    renderPackagePayContent(data) {
+        const { packageName, courseList, courseNum, packagePrices } = data;
+        /* 所含课程列表 */
+        const courseListHTMLContainer = [];
+        const newCourseList = (courseList || []).splice(0, 8);
+        newCourseList.forEach(courseItem => {
+            const { name } = courseItem;
+            courseListHTMLContainer.push(`<div class="course-item">${(name || '').replace('_', '.')}</div>`);
+        });
+        /* 课程包价格列表 */
+        const goodsListHTMLContainer = [];
+        let firstGoodsPrice = '';
+        let firstGoodsQR = 'resources/test_qr_1/15271483255269086.png';
+        packagePrices.forEach((goodsItem, index) => {
+            const { id, chargeUnit, terminalPrice, recommend, shopQR } = goodsItem;
+            if (index === 0) {
+                firstGoodsPrice = terminalPrice || '';
+            }
+            if (index === 0 && shopQR) {
+                firstGoodsQR = shopQR;
+            }
+            this.goodsArr.push(goodsItem);
+            // 一条goods对应的html结构
+            let goodsWrapperHTML = `
+                <div class="goods-item-wrapper">
+                    <div class="goods-price-terminal">${chargeUnit}:${terminalPrice}元</div>
+                    <div class="goods-price-adjust">省${1.5 * parseInt(terminalPrice) - parseInt(terminalPrice)}元</div>
+                    <div class="goods-price-original">${1.5 * parseInt(terminalPrice)}元</div>
+                </div>
+            `;
+            let goodsRecommendHTML = '<div class="goods-item-recommend">超值推荐</div>';
+            let tmpHTMLStr = goodsWrapperHTML;
+            // 超值推荐
+            if (recommend) {
+                tmpHTMLStr = goodsRecommendHTML + goodsWrapperHTML;
+            }
+            let itemHTML = `<div class="goods-item" id="goods-item-${index}" fe-role="Widget">${tmpHTMLStr}</div>`;
+            if (index === 0) {
+                itemHTML = `<div class="goods-item" id="goods-item-${index}" fe-role="Widget" fe-cfg="default_focus:yes">${tmpHTMLStr}</div>`;
+            }
+            goodsListHTMLContainer.push(itemHTML);
+        });
+        const contentHTML = `
+            <div class="pkg-title">《${packageName}》课程包:共${courseNum}个课程</div>
+            <div class="pkg-content">${courseListHTMLContainer.join('')}</div>
+            <div class="pkg-goods" fe-role="Scroll" fe-cfg="scroll_dir:v,scroll_duration:0.2,scroll_easing:linear">
+            <div class="scroll-list">${goodsListHTMLContainer.join('')}</div>
+            </div>
+            <div class="shop-qr">
+                <div class="shop-qr-img"><img src="${Consts.IMG_PATH}/${firstGoodsQR}" alt="" /></div>
+                <div class="shop-qr-desc">微信/支付宝扫码支付<span class="price">${firstGoodsPrice}元</span></div>
+            </div>
+        `;
+        const container = document.querySelector('.pay-content');
+        container.innerHTML = contentHTML;
+        this.moye.root.reRender();
+    }
+
+	onCreate(data) {
+		this.setContentView(require('../../../res/tpl/ScanToPayScene.tpl'), {}, 'ScanToPayScene', {}, () => {
+            if (data && data.id) {
+
+            } else {
+                // 由相关课程包
+                this.renderPackagePayContent(data);
+            }
+        });
+	}
+
+	onResume() {
+
+	}
+
+	onPause() {
+
+	}
+
+	onDestroy() {
+
+	}
+
+	onActive() {
+
+	}
+
+	onInactive() {
+
+	}
+
+	onBack() {
+
+	}
+
+	onOK() {
+
+	}
+
+	onKeydown(e) {
+        if (e.target.con.classList.contains('goods-item')) {
+            // 动态更换二维码及价格
+            const dynamicChangePrice = (index) => {
+                let { terminalPrice, shopQR } = this.goodsArr[index];
+                let qrDescDom = document.querySelector('.price');
+                let qrImgDom = document.querySelector('.shop-qr-img');
+                let qrImgHTML = `<img src="${Consts.IMG_PATH}/resources/test_qr_1/15271483255269086.png" alt="" />`;
+                if (shopQR) {
+                    qrImgHTML = `<img src="${Consts.IMG_PATH}/${shopQR}" alt="" />`;
+                }
+                qrImgDom.innerHTML = qrImgHTML;
+                qrDescDom.innerHTML = `${terminalPrice || ''}元`;
+            };
+            // 计算当前选中的价格
+            let goodsIndex = parseInt(e.target.id.split('-')[2]);
+            if (e.keyCode === Consts.KEYCODE_DOWN && goodsIndex < this.goodsArr.length - 1) {
+                dynamicChangePrice(goodsIndex + 1);
+            }
+            if (e.keyCode === Consts.KEYCODE_UP && goodsIndex > 0) {
+                dynamicChangePrice(goodsIndex - 1);
+            }
+        }
+	}
+
+	onKeyup() {
+
+	}
+}
+
+module.exports = ScanToPayScene;

+ 3 - 3
src/stage/index/scene/SplashScene.js

@@ -21,8 +21,8 @@ class SplashScene extends scene {
             //定时切换
              setTimeout(() => {
                //当且仅当堆栈中没有index时,方进行切换
-               if ( -1 == this.moye.focusList.indexOf('IndexScene')){
-                 this.showScene(require('./IndexScene.js'), {});
+               if ( -1 == this.moye.focusList.indexOf('WaterfallIndexScene')){
+                 this.showScene(require('./WaterfallIndexScene.js'), {});
                }
             }, 3000);
         });
@@ -51,7 +51,7 @@ class SplashScene extends scene {
     // 在使用Atv时Id对应:e.target.id
     // 非使用Atv是Id对应:e.target.id
     onOK(e) {
-        this.showScene(require('./IndexScene.js'), {});
+        this.showScene(require('./WaterfallIndexScene.js'), {});
     }
 
     onBack() {

+ 100 - 31
src/stage/index/scene/TerminalScene.js

@@ -1,37 +1,108 @@
 import userDataStorage from '../../../util/userDataStorage';
 import APIClient from '../../../util/API/APIClient';
-import {CommandBus, CMD_TYPE} from '../../../util/CommandBus';
+import { CommandBus, CMD_TYPE } from '../../../util/CommandBus';
 
 class TerminalScene extends scene {
 	constructor(scope) {
 		super(scope);
 	}
 
+	loadTerminalInfo() {
+		APIClient.getTerminalInfo((isTrue, res) => {
+			if (!isTrue || !res.success) { return; }
+			this.renderTerminalList(res.data);
+		});
+	}
+
 	renderTerminalList(dataset) {
-		let stu_no = `<li class="info-item"><div>学号</div>:${dataset.eid.replace(/(\d{4})/g, '$1 ')}</li>`;
-		let cp_name = `<li class="info-item"><div>集团名称</div>:${dataset.merchantName}</li>`;
-		let schoole_name = `<li class="info-item"><div>校区名称</div>:${dataset.name}</li>`;
-		let contact_person = `<li class="info-item"><div>联系人</div>:${dataset.merchantContactName}</li>`;
-		let phone_num = `<li class="info-item"><div>电话</div>:${dataset.merchantContactMobile}</li>`;
-		let list = document.getElementById('terminal-wrapper');
+		let stu_no = `
+			<li class="info-item">
+				<div>账号</div>:${dataset.eid.replace(/(\d{4})/g, '$1 ')}
+			</li>
+		`;
+		let cp_name = `
+			<li class="info-item">
+				<div>集团名称</div>:${dataset.merchantName}
+			</li>
+		`;
+		let schoole_name = `
+			<li class="info-item">
+				<div>校区名称</div>:${dataset.name}
+			</li>
+		`;
+		let contact_person = `
+			<li class="info-item">
+				<div>联系人</div>:${dataset.merchantContactName}
+			</li>
+		`;
+		let phone_num = `
+			<li class="info-item">
+				<div>电话</div>:${dataset.merchantContactMobile}
+			</li>
+		`;
+		let list = document.querySelector('.info-content');
 		list.innerHTML = '';
 		let listHtml = stu_no + cp_name + schoole_name + contact_person + phone_num;
 		list.innerHTML = listHtml;
 		this.moye.root.reRender();
-		this.moye.root.getWidgetById('terminal-quit').focus();
+		this.moye.root.getWidgetById('quit-account').focus();
 	}
 
-	loadTerminalInfo() {
-		APIClient.getTerminalInfo((isTrue, res) => {
+	loadTerminalBuyRecordList() {
+		APIClient.getValidProductList((isTrue, res) => {
 			if (!isTrue || !res.success) { return; }
-			this.renderTerminalList(res.data);
+			let tmp = [];
+			for (let i=0; i<6; i++) {
+				tmp = tmp.concat(res.data.recs || []);
+			}
+			this.renderBuyRecordScrollList(tmp);
 		});
 	}
 
-	onCreate() {
-		this.setContentView(require('../../../res/tpl/TerminalScene.tpl'), {}, 'TerminalScene', {}, () => {
-			this.loadTerminalInfo();
+	renderBuyRecordScrollList(recs) {
+		const timestamp2Str = (timestamp) => {
+			let date = new Date();
+			let timeStr = '';
+			try {
+				date.setTime(parseInt(timestamp));
+				let year = date.getFullYear();
+				let month = date.getMonth() + 1;
+				month = month < 10 ? ('0' + month) : month;
+				let day = date.getDate();
+				day = day < 10 ? ('0' + day) : day;
+				timeStr = `${year}年${month}月${day}日`;
+			} catch(error) {
+				console.log('date parse error:', error);
+			}
+			return timeStr;
+		}
+		const renderTableRow = (data) => {
+			const { title, beginTime, endTime } = data;
+			return `
+				<div class="front-row" fe-role="Widget">
+					<div class="first-cell">《${title}》</div>
+					<div class="second-cell">${timestamp2Str(beginTime)}</div>
+					<div class="third-cell">${timestamp2Str(endTime)}</div>
+				</div>
+			`;
+		}
+		let rowHTML = [];
+		recs.forEach(rec => {
+			rowHTML.push(renderTableRow(rec));
 		});
+		let container = document.querySelector('#buy-record-list');
+		container.innerHTML = rowHTML.join('');
+		this.moye.root.reRender();
+	}
+
+	onCreate() {
+		this.setContentView(
+			require('../../../res/tpl/TerminalScene.tpl'), {}, 'TerminalScene', {},
+			() => {
+				this.loadTerminalInfo();
+				this.loadTerminalBuyRecordList();
+			}
+		);
 	}
 
 	onResume() {
@@ -54,36 +125,34 @@ class TerminalScene extends scene {
 
 	}
 
-	// 所有事件类函数默认触发时会传递过来一个Event,其中包含着事件响应节点以及其他相关信息
-	// 查看信息:console.log(e)
-	// 获取Event节点Id的方法(前提是触发事件的节点存在Id)
-	// 在使用Atv时Id对应:e.target.id
-	// 非使用Atv是Id对应:e.target.id
+	onBack() {
+
+	}
+
 	onOK(e) {
-		if (e.target.con.classList.contains('terminal-quit')) {
+		if (e.target.con.classList.contains('quit-account')) {
 			APIClient.userLogoutAndUnbindDevice((isTrue, res) => {
 				if (!isTrue) { return; }
 				if (res.success) {
 					userDataStorage.setData(null);
 					this.showScene(require('./LoginScene.js'), {});
 					//记录用户退出行为
-					let {status, data} = CommandBus.execute({type:CMD_TYPE.APP_BHV_ACCOUNT_EXIT, payload:{}});
+					CommandBus.execute({
+						type: CMD_TYPE.APP_BHV_ACCOUNT_EXIT,
+						payload: {},
+					});
 				} else {
-				 if ( -1 != this.moye.focusList.indexOf('LoginScene')){
-					 this.hideScene({}, 'LoginScene');
-				 } else {
-					 this.showScene(require('./LoginScene.js'), {});
-				 }
-				 TVUtil.Toast.show('退出失败', res.message);
+					 if ( -1 != this.moye.focusList.indexOf('LoginScene')){
+						 this.hideScene({}, 'LoginScene');
+					 } else {
+						 this.showScene(require('./LoginScene.js'), {});
+					 }
+					 TVUtil.Toast.show('退出失败', res.message);
 				}
 			});
 		}
 	}
 
-	onBack() {
-
-	}
-
 	onKeydown() {
 
 	}

+ 404 - 0
src/stage/index/scene/WaterFallIndexScene.js

@@ -0,0 +1,404 @@
+import APIClient from '../../../util/API/APIClient';
+import CourseItem from '../../../component/CourseItem';
+import Consts from '../../../util/Consts';
+import userDataStorage from '../../../util/userDataStorage';
+import Utils from '../../../util/Utils';
+import { CommandBus, CMD_TYPE } from '../../../util/CommandBus';
+
+class WaterfallIndexScene extends scene {
+    constructor(scope) {
+        super(scope);
+        this.advertSwiper = null;
+        this.advertList = [];
+        this.waterfallSwiper = null;
+        this.clockTimeout = null;
+        this.firstCourseItemId = null;
+    }
+
+    fetchRecommendList() {
+    	APIClient.getRecommendList((isTrue, res) => {
+    		if (!isTrue) { return; }
+    		if (!res.success) {
+    			TVUtil.Toast.show('获取推荐列表失败!', 1500);
+    		}
+    		this.renderRecommendList(res.data || []);
+    	});
+    }
+
+    renderRecommendList(dataset) {
+    	let list = document.getElementById('recommend');
+    	list.innerHTML = '';
+    	let listHtml = '';
+    	for (let i in dataset) {
+    		const { id, title, subTitle, coverUrl } = dataset[i];
+    		let subject = title;
+    		let subjectSub = subTitle;
+    		let img = Consts.IMG_PATH + '/' + coverUrl;
+    		let itemDataset = { img, subject, subjectSub, buyed: false };
+    		if (0 == i) {
+    			this.firstCourseItemId = `product-item-recommend-${id}`;
+            }
+    		listHtml += `
+                <div class="product-item" id="product-item-recommend-${id}" fe-role="Widget">
+                    ${CourseItem.createHTMLString(itemDataset)}
+                </div>
+            `;
+    	}
+    	list.innerHTML = listHtml;
+    	this.moye.root.reRender();
+    	//默认焦点设置
+    	if (this.firstCourseItemId) {
+    		this.moye.root.getWidgetById(this.firstCourseItemId).focus();
+    	}
+        // 推荐列表渲染完成后,请求待续费产品列表
+        // this.fetchRenewProductList();
+    }
+
+    fetchAdvertList() {
+    	APIClient.getRecommendPosters((isTrue, res) => {
+            if (!isTrue || !res.success) { return; }
+            this.renderAdvertList(res.data.recs || []);
+            this.advertList = res.data.recs;
+        });
+    }
+
+    renderAdvertList(recs) {
+        // 构建swiper dom结构
+        let sliderHTML = [];
+        recs.forEach(rec => {
+            const { img, pid, type } = rec;
+            sliderHTML.push(`<div class="swiper-slide"><img src="${Consts.IMG_PATH}/${img}" alt="" /></div>`)
+        });
+        let swiperHTML = `
+            <div id="swiper-advert" class="swiper-container-advert swiper-container" fe-role="Widget">
+                <div class="swiper-wrapper">${sliderHTML.join('')}</div>
+                <div class="swiper-pagination swiper-pagination-advert"></div>
+            </div>
+        `;
+        let container = document.getElementById('advert-carousel');
+        container.innerHTML = swiperHTML;
+        // 创建swiper对象
+        this.advertSwiper = new Swiper('.swiper-container-advert', {
+            direction: 'horizontal',
+            autoplay: true,
+            pagination: {
+                el: '.swiper-pagination-advert',
+                bulletElement: 'li',
+            },
+        });
+        this.moye.root.reRender();
+    }
+
+    fetchRenewProductList() {
+    	APIClient.getRenewProductList((isTrue, res) => {
+    		if (!isTrue || !res.success) { return; }
+            if (res.data && res.data.totalNum) {
+            	this.showScene(require('./RenewAlertScene.js'), { recs: res.data.recs });
+            }
+    	});
+    }
+
+    fetchWaterfallList() {
+    	APIClient.getWaterfallList((isTrue, res) => {
+    		if (!isTrue || !res.success) { return; }
+    		this.renderWaterfallList(res.data || []);
+    	});
+    }
+
+    renderWaterfallList(tagList) {
+        /* 校验数据格式 */
+        if (!tagList || !Array.isArray(tagList)) {
+            return;
+        }
+        /* 工具一: 切割数组为多个子数组 */
+        const subGroupSpliter = (array, subGroupLength) => {
+            let cursor = 0;
+            let newArray = [];
+            while (cursor < array.length) {
+                newArray.push(array.slice(cursor, cursor += subGroupLength));
+            }
+            return newArray;
+        }
+        /* 工具二: 将课程数据转成html字符串 */
+        const courseDataTransfer = (groupIndex, dataset) => {
+            let listHTML = '';
+            dataset.forEach(item => {
+                const { id, title, subTitle, coverUrl } = item;
+                const courseItemDataset = {
+                    img: Consts.IMG_PATH + '/' + coverUrl,
+                    subject: title,
+                    subjectSub: subTitle,
+                    buyed: false,
+                };
+                listHTML += `
+                    <div class="product-item" fe-role="Widget" id="product-item-${groupIndex}-${id}">
+                        ${CourseItem.createHTMLString(courseItemDataset)}
+                    </div>
+                `;
+            });
+            return listHTML;
+        }
+        /* 如果没有系列课程,不显示分页及向下的指示箭头 */
+        if (tagList.length) {
+            document.querySelector('.arrow_down').style.display = 'block';
+        }
+        /* 构造{ serialName: 'xx', courseList: []} 格式的数据组 */
+        const groups = [];
+        for (let index in tagList) {
+            const tag = tagList[index];
+            const { name, recs } = tag;
+            // 去掉无内容标签
+            if (!recs || !recs.length) {
+                continue;
+            }
+            // 每5个分割
+            const splitedRecs = subGroupSpliter(recs, 5);
+            // 构造数据组
+            splitedRecs.forEach((oneRecs, index) => {
+                let serialName = '';
+                if (index === 0) {
+                    serialName = name;
+                }
+                groups.push({
+                    serialName,
+                    courseList: oneRecs,
+                });
+            });
+        }
+        /* 将groups中内容构造成html字符串 */
+        const groupHTMLArr = [];
+        groups.forEach((group, groupIndex) => {
+            const { serialName, courseList } = group;
+            if (serialName) {
+                groupHTMLArr.push(
+                    `
+                    <div class="group-wrapper">
+                        <div class="group-name">${serialName}</div>
+                        <div class="group-list">${courseDataTransfer(groupIndex, courseList)}</div>
+                    </div>
+                    `
+                );
+            } else {
+                groupHTMLArr.push(
+                    `
+                    <div class="group-wrapper">
+                        <div class="group-list">${courseDataTransfer(groupIndex, courseList)}</div>
+                    </div>
+                    `
+                );
+            }
+        });
+        /* 将groupHTML内容构造成多个slider */
+        const sliderGroups = subGroupSpliter(groupHTMLArr, 2);
+        const sliders = [];
+        sliderGroups.forEach(sliderGroup => {
+            sliders.push(
+                `
+                <div class="waterfall-content">
+                    <div class="scroll-list">
+                        ${sliderGroup.join('')}
+                    </div>
+                </div>
+                `
+            );
+        });
+        /* 将sliders插入到页面dom中 */
+        let swiperContainer = document.getElementById('waterfall-swiper');
+        sliders.forEach((slider, sliderIndex) => {
+            let slideDom = document.createElement('div');
+            slideDom.setAttribute('class', 'swiper-slide');
+            slideDom.setAttribute('fe-role', 'Switch');
+            slideDom.setAttribute('id', `slide-${sliderIndex + 1}`);
+            if (sliderIndex < sliders.length - 1) {
+                slideDom.innerHTML = slider + '<div class="arrow_down"><img src="assets/img/WaterfallIndexScene/arrow_down.png" alt="" /></div>';
+            } else {
+                slideDom.innerHTML = slider;
+            }
+            swiperContainer.appendChild(slideDom);
+        });
+        /* 注册swiper */
+        this.waterfallSwiper = new Swiper('.swiper-container-waterfall', {
+            direction: 'vertical',
+            pagination: {
+                el: '.swiper-pagination-waterfall',
+                bulletElement: 'li',
+            },
+        });
+        /* 重新渲染下,使新构造的swiper生效 */
+        this.moye.root.reRender();
+    }
+
+    renderDigitalClock() {
+        const clock = () => {
+            window.clearTimeout(this.clockTimeout);
+            let dt = new Date();
+            let h = dt.getHours();
+            let m = dt.getMinutes();
+            let s = dt.getSeconds();
+            let clockHTML = `${(h < 10 ? '0' : '') + h}<span style="visibility: ${s % 2 ? 'visible' : 'hidden'}">:</span>${(m < 10 ? '0' : '') + m}`;
+            let clockDom = document.querySelector(".clock");
+            clockDom.innerHTML = clockHTML;
+            this.clockTimeout = window.setTimeout(clock, 1000);
+        }
+        clock();
+    }
+
+    /**
+    * 使用设备号deviceCode刷新token
+    */
+    refreshToken() {
+        // 判断本地存储是否保存deviceCode,没有则跳转到登录界面
+        if (!localStorage.getItem('deviceCode')) {
+            if ( -1 != this.moye.focusList.indexOf('LoginScene')) {
+                this.hideScene({}, 'LoginScene');
+            } else {
+                this.showScene(require('./LoginScene.js'), {});
+            }
+            return;
+        }
+        // 取得deviceCode,换取新token
+        APIClient.refreshTokenByDeviceCode(
+            (isTrue, res) => {
+                // 正常获取到token,进行下一步请求和渲染动作
+                if (!isTrue) { return; }
+                if (res.success) {
+                    // 保存终端信息
+                    userDataStorage.setData(res.data);
+                    // 渲染数字时钟
+                    this.renderDigitalClock();
+                    // 请求推荐列表
+                    this.fetchRecommendList();
+                    // 请求广告位图片列表
+                    this.fetchAdvertList();
+                    // 请求瀑布流数据
+                    this.fetchWaterfallList();
+                    // 调安卓记录用户登录事件
+                    let { status, data } = CommandBus.execute({
+                        type: CMD_TYPE.APP_BHV_USER_LOGIN,
+                        payload: {
+                            "eid": userDataStorage.getData().eid,
+                            "uid": userDataStorage.getData().uid.toString(),
+                        },
+                    });
+                // 未正确获取到token,跳转到登录界面
+                } else {
+                    if ( -1 != this.moye.focusList.indexOf('LoginScene')) {
+                    this.hideScene({}, 'LoginScene');
+                    } else {
+                    this.showScene(require('./LoginScene.js'), {});
+                    }
+                }
+            }
+        );
+    }
+
+    onCreate() {
+        this.setContentView(
+            require('../../../res/tpl/WaterfallIndexScene.tpl'),
+            { 'title': '2B双师标准教学平台' },
+            'WaterfallIndexScene',
+            {},
+            () => {
+                // 注册安卓按键事件
+                setAndroidEvent('keydown', 40);
+                // 验证本地存储中设备号,丢失则重新保存
+                if (!localStorage.getItem('deviceCode')) {
+                    localStorage.setItem(
+                        'deviceCode',
+                        window.efunbox ? window.efunbox.getUuidForDevice() : Utils.getUuidForWeb()
+                    );
+                }
+                // 渲染完成使用deviceCode刷新token
+                this.refreshToken();
+            }
+        );
+    }
+
+    onPause() {
+        // 页面被覆盖,清除定时器,销毁时钟
+        window.clearTimeout(this.clockTimeout);
+        let clockDom = document.querySelector('.clock');
+        clockDom.innerHTML = '';
+    }
+
+    onDestroy() {
+
+    }
+
+    onActive() {
+
+    }
+
+    onInactive() {
+
+    }
+
+    onResume(data) {
+        // 重现页面,重新创建时钟
+        this.renderDigitalClock();
+        // 登录页恢复到此页重新验证用户
+        if (data && data.success) {
+            this.refreshToken();
+        }
+    }
+
+    onBack() {
+        if (this.waterfallSwiper.activeIndex === 0) {
+            this.showScene(require('./QuitConfirmScene.js'), {});
+            return true;
+        } else {
+            this.waterfallSwiper.slideTo(0, 1000, false);
+            this.moye.root.getWidgetById(this.firstCourseItemId).focus();
+            return true;
+        }
+    }
+
+    onOK(e) {
+        /* 首屏入口 */
+        if (e.target.con.classList.contains('entrance')) {
+            let type = e.target.id.replace('entrance-', '');
+            if (type === 'terminal') {
+                this.showScene(require('./TerminalScene.js'), {});
+            } else if (type === 'download') {
+                this.showScene(require('./DownloadCollectionScene.js'), {});
+            } else {
+                this.showScene(require('./CLScene.js'), { type });
+            }
+        } else if (e.target.con.classList.contains('product-item')) {
+            let id = e.target.id.split('-')[3];
+            this.showScene(require('./CourseScene.js'), { id });
+        } else if (e.target.con.classList.contains('swiper-container-advert') && this.advertList.length) {
+            let currentAdvert = this.advertList[this.advertSwiper.activeIndex];
+            const { pid, type } = currentAdvert;
+            if (type === Consts.TYPE_COURSE) {
+                this.showScene(require('./CourseScene.js'), { id: pid });
+            } else if (type === Consts.TYPE_TRAINING) {
+                this.showScene(require('./CourseScene.js'), { id: pid });
+            }
+        }
+    }
+
+    onKeydown(e) {
+        const isSwitchSlide = () => {
+            let currentFocusId = FocusEngine.getFocusedLeaf().id;
+            let currentFocus = document.getElementById(currentFocusId);
+            let currentSlideIndex = this.waterfallSwiper.activeIndex;
+            let currentSlide = document.getElementById(`slide-${currentSlideIndex}`);
+            return currentSlide.contains(currentFocus) ? false : true;
+        }
+        /* 方向键向下 */
+        if (e.keyCode === Consts.KEYCODE_DOWN && this.waterfallSwiper && isSwitchSlide()) {
+            this.waterfallSwiper.slideNext();
+        }
+        /* 方向键向上 */
+        if (e.keyCode === Consts.KEYCODE_UP && this.waterfallSwiper && isSwitchSlide()) {
+            this.waterfallSwiper.slidePrev();
+        }
+    }
+
+    onKeyup() {
+
+    }
+}
+
+module.exports = WaterfallIndexScene;

+ 1 - 43
src/stage/index/style/CLScene.less

@@ -69,54 +69,12 @@
         width: 15.5rem;
         height: 100%;
     }
-    .control-panel {
-        float: right;
-        margin-top: 0.34rem;
-        margin-right: 0.4rem;
-        width: 1.82rem;
-        height: 0.86rem;
 
-        .control-btn {
-            border: solid unit(@borderSize, rem) transparent;
-            border-radius: 0.5rem;
-            &.fe-focus {
-                .after-focus(@borderSize; #ffe100);
-            }
-            img {
-                width: 0.78rem;
-                height: 0.78rem;
-            }
-        }
-
-        .search-btn-frame {
-            float: left;
-            .control-btn;
-        }
-
-        .shopping-cart-btn-frame {
-            float: right;
-            .control-btn;
-        }
-
-        .cart-num {
-            position: absolute;
-            top: .3rem;
-            right: .3rem;
-            width: .4rem;
-            height: .4rem;
-            color: #fff;
-            line-height: .4rem;
-            border-radius: .3rem;
-            background-color: #f40;
-            font-size: .26rem;
-            text-align: center;
-            display: none;
-        }
-    }
     #cl-right-content-scroll {
         position: relative;
         overflow: hidden;
         width: 14.2rem;
+        margin-top: 1.2rem;
         margin-left: 0.43rem;
         height: 9.66rem;
         ul {

+ 62 - 87
src/stage/index/style/CourseScene.less

@@ -96,14 +96,14 @@
 				}
 
 				&.detail {
-					background-image: url("assets/img/CourseScene/course_buy.png");
+					background-image: url("assets/img/CourseScene/detail.png");
 
 					&.selected {
-						background-image: url("assets/img/CourseScene/course_buyed.png");
+						background-image: url("assets/img/CourseScene/detail_selected.png");
 					}
 
 					&::after {
-						content: '课程购买';
+						content: '课程介绍';
 					}
 
 					&.fe-focus {
@@ -150,25 +150,12 @@
 				&.cart {
 					background-image: url("assets/img/CourseScene/cart.png");
 
-					.cart-num {
-						position: absolute;
-						top: -0.1rem;
-						right: -0.1rem;
-						width: .6rem;
-						height: .6rem;
-						color: #fff;
-						line-height: .6rem;
-						border-radius: .3rem;
-						background-color: #f40;
-						display: none;
-					}
-
 					&.selected {
 						background-image: url("assets/img/CourseScene/cart_selected.png");
 					}
 
 					&::after {
-						content: '购物车';
+						content: '购买';
 					}
 
 					&.fe-focus {
@@ -199,6 +186,7 @@
 				.text-wrapper {
 					position: relative;
 					box-shadow: 0.03rem 0.03rem 0.1rem rgba(0, 0, 0, 0.3);
+					// white-space: nowrap;
 					float: left;
 					width: 6.19rem;
 					height: 1.1rem;
@@ -207,22 +195,15 @@
 					background-color: #fff;
 					margin: 0 0.26rem 0.3rem;
 					border-radius: 0.35rem;
-					// border: 0.05rem solid transparent;
+					border: 0.05rem solid transparent;
 					font-size: .48rem;
 					color: #404040;
 					padding: 0 0.4rem;
+					//margin-left: 0.66rem;
 					&.fe-focus {
 						.after-focus(@borderSize; #ff5050; .1rem; rgba(0,0,0,0.5));
 					}
-					.free-flag {
-						width: .86rem;
-						height: .86rem;
-						position: absolute;
-						top: -0.05rem;
-						right: -0.05rem;
-						background: url('assets/img/CourseScene/icon_free.png') no-repeat center;
-						background-size: cover;
-					}
+
 				}
 
 				.download-btn-lesson {}
@@ -235,7 +216,7 @@
 					height: 1.1rem;
 					line-height: 1.1rem;
 					overflow: hidden;
-					border-radius: 0.33rem;
+					border-radius: 0.30rem;
 					background-image:url('assets/img/CourseScene/download_btn_list_undownload.png');
 					background-repeat: no-repeat;
 					background-size: cover;
@@ -290,7 +271,7 @@
 						}
 					}
 
-			        .download-btn-lesson-icon-ready {
+	        		.download-btn-lesson-icon-ready {
 						position: relative;
 						box-shadow: 0.03rem 0.03rem 0.1rem rgba(0, 0, 0, 0.3);
 						width: 1.60rem;
@@ -309,15 +290,15 @@
 					}
 
 					.download-btn-lesson-icon-ongoing {
-						.download-btn-lesson-icon-ready;
-						background-image:url('assets/img/CourseScene/download_btn_icon_ongoing.gif');
+							.download-btn-lesson-icon-ready;
+							background-image:url('assets/img/CourseScene/download_btn_icon_ongoing.gif');
 					}
 
 					.download-btn-lesson-icon-success {
-						.download-btn-lesson-icon-ready;
-						background-image:url('assets/img/CourseScene/download_btn_icon_success.png');
+							.download-btn-lesson-icon-ready;
+							background-image:url('assets/img/CourseScene/download_btn_icon_success.png');
 					}
-		        }//lesson-wrapper
+				}//lesson-wrapper
 			}
 		}
 
@@ -368,52 +349,6 @@
 				}
 			}
 
-			.btn-panel {
-				margin: 0 3.1rem
-			}
-
-			.btn {
-				position: relative;
-				float: left;
-				width: 3.9rem;
-				height: 1.1rem;
-				border-radius: .55rem;
-				margin: -.55rem .16rem 0 .16rem;
-				overflow: hidden;
-				background-repeat: no-repeat;
-				background-position: center;
-				background-size: cover;
-				padding: .14rem 0 0 1.4rem;
-				color: white;
-				font-size: .3rem;
-
-				&.goods-0 {
-					background-image: url('assets/img/CourseScene/detail/month_add_cart.png');
-				}
-
-				&.goods-1 {
-					background-image: url('assets/img/CourseScene/detail/season_add_cart.png');
-				}
-
-				&.goods-2 {
-					background-image: url('assets/img/CourseScene/detail/year_add_cart.png');
-				}
-
-				&.added{
-					background-image: url('assets/img/CourseScene/detail/added_cart.png');
-				}
-
-				&.fe-focus {
-					padding-top: .1rem;
-					.after-focus(@borderSize; #ff5050; .1rem; rgba(0,0,0,0.5));
-				}
-
-				p {
-					font-size: .24rem;
-					text-decoration: line-through;
-				}
-			}
-
 			.renewal-btn {
 				position: relative;
 				width: 3.9rem;
@@ -507,23 +442,25 @@
 				margin-right: 1.7rem;
 				width: 15.75rem;
 				height: 6.35rem;
-				padding: 0.3rem 0.5rem 0.3rem 0.3rem;
+				padding: 0.3rem 0.2rem 0.3rem 0.2rem;
 				border-radius: 0.2rem;
 				font-size: 0;
 				background-color: #fff;
 
+				/* 轮播图 */
 				.periphery-slide {
 					display: inline-block;
 					width: 5.75rem;
 					height: 5.75rem;
-					margin-right: 0.4rem;
+					margin-right: 0.3rem;
 					background-color: #eee;
 				}
 
+				/* 配套描述 */
 				.periphery-detail {
 					display: inline-block;
 					vertical-align: bottom;
-					width: 8.7rem;
+					width: 5.8rem;
 					height: 5.75rem;
 
 					.periphery-name {
@@ -537,8 +474,8 @@
 					}
 
 					.periphery-price {
-						margin-top: 0.3rem;
-						margin-bottom: 0.38rem;
+						margin-top: 0.2rem;
+						margin-bottom: 0.2rem;
 						font-size: 0.48rem;
 						line-height: 1;
 						color: #ff7e00;
@@ -546,11 +483,12 @@
 
 					.periphery-desc {
 						width: 100%;
-						height: 2.88rem;
+						height: 4.58rem;
 						overflow: hidden;
 						font-size: 0.3rem;
-						line-height: 0.48rem;
+						line-height: 0.45rem;
 						color: #000;
+						text-align: justify;
 					}
 
 					.periphery-icon {
@@ -578,6 +516,43 @@
 						}
 					}
 				}
+
+				/* 购买二维码 */
+				.periphery-shopqr {
+					display: inline-block;
+					vertical-align: bottom;
+					width: 3.4rem;
+					height: 5.75rem;
+					padding-left: 0.3rem;
+					.periphery-shopqr-wrapper {
+						height: 4.55rem;
+						width: 100%;
+						margin: .6rem 0;
+						padding: .2rem;
+						border: solid unit(.03, rem) #f5f5f5;
+						border-radius: .25rem;
+						.shopqr-desc {
+							height: 1rem;
+							width: 100%;
+							margin-top: .25rem;
+							margin-bottom: .2rem;
+							.shopqr-desc-big {
+								font-size: .36rem;
+							}
+							.shopqr-desc-sub {
+								font-size: .28rem;
+							}
+						}
+						.shopqr-img {
+							width: 2.7rem;
+							height: 2.7rem;
+							img {
+								width: 100%;
+								height: 100%;
+							}
+						}
+					}
+				}
 			}
 		}
 	}

+ 269 - 0
src/stage/index/style/DownloadCollection.less

@@ -0,0 +1,269 @@
+@import './Mixins.less';
+@import './component/GoodsItem.less';
+@import './component/CourseItem.less';
+
+@tagHeight: 1.05rem;
+@marginTop: 1.77rem;
+.custom-focus(@borderSize:0; @borderColor: transparent; @boxShadowSize: 0; @boxShadowColor: transparent) {
+	transform: scale3d(1.07, 1.07, 1.07);
+	-webkit-transform: scale3d(1.07, 1.07, 1.07);
+	border: solid unit(@borderSize, rem) @borderColor;
+	z-index: 9999;
+}
+
+#DownloadCollectionScene {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    background: url('./assets/img/DownloadCollection/background.jpg') center no-repeat;
+    background-size: 100% 100%;
+
+    // 1.左侧面板
+    #dc-left-panel {
+        float: left;
+        width: 3.7rem;
+        height: 100%;
+        #dc-left-tab-scroll {
+            padding-top: @marginTop;
+            position: relative;
+            overflow: hidden;
+            height: 8.55rem;
+        }
+        .tag-item {
+            color: white;
+            font-size: 0.42rem;
+            height: @tagHeight;
+            text-align: center;
+            span {
+                position: relative;
+                height: 0.42rem;
+                top: 0.2rem;
+            }
+            &.fe-cache {
+                color: white;
+                background: #4d92df;
+            }
+            &.fe-focus {
+                color: #ffe100;
+                font-weight: bolder;
+                background: #4d92df;
+            }
+        }
+    }
+
+    // 2.右侧面板
+    #dc-right-panel {
+        float: right;
+        width: 15.5rem;
+        height: 100%;
+
+        // 2-1.下载table背景样式
+        .download-bg-wrapper {
+            z-index: 0;
+            position: absolute;
+            margin-top: @marginTop;
+          	width: 14.36rem;
+          	height: 8.34rem;
+          	border-radius: 0rem 0.3rem 0.3rem 0rem;
+          	background-color: #244b7e;
+          	text-align: center;
+
+            // table-header-background
+            .download-bg-header {
+      			z-index: 0;
+      			background-color: #5a70d6;
+      			border-radius: 0rem 0.3rem 0rem 0rem;
+      			height: @tagHeight;
+            }
+
+            // table-body-row-split-line
+    		.horizon-line {
+      			z-index: 0;
+      			height: 0.81rem;
+      			width: 14.35rem;
+                border-bottom: 0.02rem solid #053864;
+      			margin: 0 auto;
+      			&.first-line {
+    				height: @tagHeight;
+    				border-bottom: none;
+                }
+    		}
+
+            // table-body-background-row
+    		.back-row {
+                z-index: 2;
+                height: 0.81rem;
+                text-align: center;
+                position: relative;
+                float: left;
+                line-height: 0.81rem;
+                font-size: 0.3rem;
+                color: white;
+                display: table-row;
+                // margin-left: 0.38rem;
+                div {
+                	display: table-cell;
+                    vertical-align: middle;
+                }
+                .right-border {
+                	height: 0.81rem;
+                	border-right: 0.02rem solid #053864;
+                }
+                .one {
+                	width: 2rem;
+                	text-align: center;
+                	.right-border;
+                }
+                .two {
+                	width: 3.37rem;
+                	.right-border;
+                }
+                .three {
+                	width: 3.87rem;
+                	.right-border;
+                }
+                .four {
+                	width: 1.5rem;
+                	.right-border;
+                }
+                .five {
+                	width: 2rem;
+                	.right-border;
+                }
+                .six {
+                	width: 2.5rem;
+                }
+            }
+        }
+
+        // 2-2.下载table行样式
+        .row {
+			z-index: 1;
+			height: 0.81rem;
+			text-align: center;
+            vertical-align: middle;
+			position: relative;
+			font-size: 0.3rem;
+			color: white;
+			display: table-row;
+			margin: 0 auto;
+			div {
+				display: table-cell;
+                vertical-align: middle;
+			}
+			.right-border {
+				border-right: 0.02rem solid #053864;
+			}
+			.one {
+				width: 2.02rem;
+				text-align: center;
+			}
+			.two {
+				width: 3.40rem;
+			}
+			.three {
+				width: 3.91rem;
+			}
+			.four {
+				width: 1.5rem;
+			}
+			.five {
+				width: 2.02rem;
+			}
+			.six {
+                width: 2.5rem;
+                padding: 0rem 0.1rem 0rem 0.2rem;
+                #download-btn-wrapper {
+                    // 第6列中快速进入按钮
+                    .download-enter-btn {
+                    	width: 1.25rem;
+                    	height: 0.4rem;
+                    	&.fe-focus {
+                			.custom-focus(0.032rem; #ffe100; 0; rgba(0,0,0,0.5));
+                			border-radius: 0.2rem 0.2rem 0.2rem 0.2rem;
+                    	}
+                    }
+                    // 第6列中删除按钮
+                    .download-del-btn {
+                        width: 0.65rem;
+                        height: 0.4rem;
+                        &.fe-focus {
+                        	.custom-focus(0.032rem; #ffe100; 0; rgba(0,0,0,0.5));
+                        	border-radius: 0.2rem 0.2rem 0.2rem 0.2rem;
+                        }
+                    }
+                }
+            }
+            &.row-header {
+                height: 1.06rem;
+            }
+        }
+
+        // 2-3.下载table表头
+        .header {
+            height: @tagHeight;
+            text-align: center;
+            position: absolute;
+            margin-top: 0;
+        }
+
+        // 2-4.表层数据
+      	.download-content-wrapper {
+            z-index: 2;
+            position: absolute;
+            margin-top: (@marginTop + @tagHeight);
+          	width: 14.36rem;
+          	height: 7.29rem;
+          	text-align: center;
+            display: table;
+            overflow: hidden;
+
+    		.scroll-lines-wrapper {
+      			z-index: 1;
+            // margin-top: (@marginTop + @tagHeight);
+      			position: absolute;
+      			// margin-top: 0;
+    		}
+      	}
+    }
+
+    #dc-right-content-scroll {
+        position: relative;
+        overflow: hidden;
+        width: 14.2rem;
+        margin-left: 0.43rem;
+        margin-top: 1.3rem;
+        height: 9.66rem;
+        ul {
+            overflow: hidden;
+            padding-bottom: 0.18rem;
+        }
+        .item {
+            float: left;
+	          margin-bottom: 0.1rem;
+            width: 3.52rem;
+            height: 4.84rem;
+
+            //课程item组件在当前scene的margin需要在使用scene的样式中定义
+            //周边商品item组件在当前scene的margin需要在使用scene的样式中定义
+            .course-item-frame,
+            .goods-item-frame {
+                margin: 0.18rem 0 0 0.18rem;
+            }
+            //自定义课程item在当前scene的focus样式
+            //自定义周边商品item在当前scene的focus样式
+            &.fe-focus .course-item-frame,
+            &.fe-focus .goods-item-frame {
+                .after-focus(@borderSize; #ffe100);
+            }
+        }
+
+        #no-content-message {
+            font-size: .5rem;
+            color: white;
+            position: absolute;
+            left: 46%;
+            top: 45%;
+        }
+    }
+}

+ 0 - 213
src/stage/index/style/DownloadScene.less

@@ -1,213 +0,0 @@
-@import "./Mixins.less";
-
-#DownloadManagerScene {
-	position: absolute;
-	top: 0;
-	left: 0;
-	width: 100%;
-	height: 100%;
-	overflow: hidden;
-	text-align: center;
-
-	.download-manager-bg {
-		position: absolute;
-		top: 0;
-		left: 0;
-		z-index: -1;
-		width: 100%;
-		height: 100%;
-		img {
-			width: 100%;
-			height: 100%;
-		}
-	}
-
-	.local-download-icon{
-		float: left;
-		position: relative;
-		left:0.5rem;
-		top:0.3rem;
-		width:3rem;
-		img {
-			float: left;
-			width: 1rem;
-		}
-		div{
-			float: left;
-			font-size: 0.3rem;
-			color: white;
-			margin-top: 0.3rem;
-			margin-left: 0.2rem;
-		}
-	}
-
-	.background-wrapper{
-		z-index: 0;
-		position: absolute;
-		left: 0.4rem;
-		margin: 1.55rem 1.25rem;
-		width: 16rem;
-		height: 8.29rem;
-		border-radius: 0.3rem 0.3rem 0.3rem 0.3rem;
-		background-color: #244b7e;
-		text-align: center;
-
-		.background-header{
-			z-index: 0;
-			background-color:#5a70d6;
-			border-radius: 0.3rem 0.3rem 0rem 0rem;
-			height:0.9rem;
-		}
-
-		.horizon-line {
-			z-index: 0;
-			height:0.82rem;
-			width: 15.6rem;
-      		border-bottom: 0.02rem solid #053864;
-			margin: 0 auto;
-			&.first-line{
-				height: 0.9rem;
-				border-bottom: none;
-			}
-		}
-
-		.back-row {
-			z-index: 2;
-			height: 0.82rem;
-			text-align: center;
-			position:relative;
-			float: left;
-			line-height: 0.82rem;
-			font-size: 0.3rem;
-			color: white;
-			display:table-row;
-			margin-left: 0.38rem;
-			div {
-				display:table-cell;
-      			vertical-align:middle;
-			}
-			.right-border {
-				height: 0.82rem;
-				border-right: 0.02rem solid #053864;
-			}
-			.one {
-				width:2rem;
-				.right-border;
-				text-align: center;
-			}
-			.two {
-				width:3.87rem;
-				.right-border;
-			}
-			.three {
-				width:3.37rem;
-				.right-border;
-			}
-			.four {
-				width:1.5rem;
-				.right-border;
-			}
-			.five {
-				width:2rem;
-				.right-border;
-			}
-			.six {
-				width:2.9rem;
-			}
-		}
-	}
-
-	.content-wrapper {
-		z-index: 2;
-		position: absolute;
-		width: 100%;
-		margin-left: 0.38rem;
-		display:table;
-		height: 7.39rem;
-    	overflow: hidden;
-
-		.scroll-lines-wrapper{
-			z-index: 1;
-			position: absolute;
-			margin-top: 0;
-		}
-	}//content-wrapper
-
-	.row {
-		z-index: 1;
-		height: 0.82rem;
-		text-align: center;
-		position:relative;
-		font-size: 0.3rem;
-		color: white;
-		display:table-row;
-		margin: 0 auto;
-		div {
-			display:table-cell;
-  			vertical-align:middle;
-		}
-		.right-border {
-			border-right: 0.02rem solid #053864;
-		}
-		.one {
-			width:2rem;
-			text-align: center;
-		}
-		.two {
-			width:3.87rem;
-		}
-		.three {
-			width:3.37rem;
-		}
-		.four {
-			width:1.5rem;
-		}
-		.five {
-			width:2rem;
-		}
-		.six {
-			width:2.9rem;
-			text-align: center;
-
-			.download-enter-btn {
-				width: 1.7rem;
-				height: .6rem;
-				border: .05rem solid transparent;
-				.img-btn {
-					height: 100%;
-					width: 100%;
-				}
-
-				&.fe-focus {
-					border: .05rem solid #ffe100;
-					border-radius: .25rem;
-				}
-			}
-
-			.download-del-btn {
-				width: 1rem;
-				height: .6rem;
-				border: .05rem solid transparent;
-				.img-btn{
-					height: 100%;
-					width: 100%;
-				}
-				&.fe-focus {
-					border: .05rem solid #ffe100;
-					border-radius: .25rem;
-				}
-			}
-		}
-		&.row-header{
-			height: 0.9rem;
-		}
-	}//row
-
-	.header {
-		height: 0.9rem;
-		text-align: center;
-		position: absolute;
-		margin-top: 0;
-		padding-left: 0.38rem;
-	}
-}

+ 49 - 64
src/stage/index/style/GlobalGoodDetail.less

@@ -4,7 +4,7 @@
     position: absolute;
     width: 100%;
     height: 100%;
-    background: url('./assets/img/GlobalGoodDetail/bg.jpg') center no-repeat;
+    background: url('./assets/img/GlobalGoodDetail/background.jpg') center no-repeat;
     background-size: 100% 100%;
 
     .control-panel {
@@ -25,33 +25,6 @@
                 height: 0.78rem;
             }
         }
-
-        /*
-        .search-btn-frame {
-            float: left;
-            .control-btn;
-        }
-        */
-
-        .shopping-cart-btn-frame {
-            float: right;
-            .control-btn;
-        }
-
-        .cart-num {
-            position: absolute;
-            top: .3rem;
-            right: .3rem;
-            width: .4rem;
-            height: .4rem;
-            color: #fff;
-            line-height: .4rem;
-            border-radius: .3rem;
-            background-color: #f40;
-            font-size: .26rem;
-            text-align: center;
-            display: none;
-        }
     }
 
     .detail-panel {
@@ -65,62 +38,74 @@
             display: inline-block;
             width: 5.75rem;
             height: 5.75rem;
-
-            margin: 0.29rem;
+            margin: 0.29rem 0.2rem 0.29rem 0.29rem;
         }
 
         .detail-text-panel {
-            float: right;
-            width: 9.0rem;
+            display: inline-block;
+            vertical-align: bottom;
+            width: 5.85rem;
             height: 5.75rem;
-            margin: 0.29rem 0.29rem 0.29rem 0;
+            margin: 0.29rem 0.2rem 0.29rem 0;
             .title {
                 color: #000;
                 font-size: 0.36rem;
                 font-weight: 800;
             }
-
             .price {
                 color: #ff7e00;
                 font-size: 0.48rem;
-                margin-top: 0.3rem;
+                line-height: 1;
+                margin-top: 0.2rem;
             }
-
             .desc {
                 color: #000;
                 font-size: 0.3rem;
-                margin-top: 0.38rem;
-                height: 2.6rem;
+                margin-top: 0.2rem;
+                width: 100%;
+                height: 4.29rem;
+                line-height: .45rem;
+                overflow: hidden;
+                text-align: justify;
             }
-            .detail-control-panel {
-                width: 5.84rem;
-                // height: unit(@borderSize * 2 + 0.94, rem);
-                margin-top: 0.16rem;
-
-                .control-btn {
-                    border: solid unit(@borderSize, rem) transparent;
-                    border-radius: 0.24rem;
-                    &.fe-focus {
-                        .after-focus(@borderSize; #ffe100);
-                    }
-                    img {
-                        width: 2.77rem;
-                        height: 0.94rem;
-                    }
-                }
-
-                .add-shop-cart-btn-frame {
-                    float: left;
-                    .control-btn;
-                }
+        }
 
-                .play-btn-frame {
-                    float: right;
-                    .control-btn;
-                }
+        // 二维码
+        .shopqr {
+          display: inline-block;
+          vertical-align: bottom;
+          width: 3.1rem;
+          height: 5.75rem;
+          margin: .29rem 0;
+          .shopqr-wrapper {
+            	height: 4.55rem;
+            	width: 100%;
+            	margin: .6rem 0;
+            	padding: .2rem;
+            	border: solid unit(.03, rem) #f5f5f5;
+            	border-radius: .25rem;
+            	.shopqr-desc {
+            		height: 1rem;
+            		width: 100%;
+            		margin-top: .25rem;
+            		margin-bottom: .2rem;
+            		.shopqr-desc-big {
+            			font-size: .36rem;
+            		}
+            		.shopqr-desc-sub {
+            			font-size: .28rem;
+            		}
+            	}
+            	.shopqr-img {
+            		width: 2.7rem;
+            		height: 2.7rem;
+            		img {
+            			width: 100%;
+            			height: 100%;
+            		}
+            	}
             }
         }
-
     }
 
     .concerned-panel {

+ 0 - 145
src/stage/index/style/IndexScene.less

@@ -1,145 +0,0 @@
-@import './component/CourseItem.less';
-
-#IndexScene {
-	position: absolute;
-	width: 100%;
-	height: 100%;
-	padding: 0.05rem 1.2rem 0;
-
-	.index-bg {
-		position: absolute;
-		top: 0;
-		left: 0;
-		z-index: -1;
-		width: 100%;
-		height: 100%;
-		img {
-			position: absolute;
-			top: 0;
-			left: 0;
-			width: 100%;
-			height: 100%;
-		}
-	}
-
-	.m-header-user{
-		height: 0.96rem;
-		margin-top: 1rem;
-
-		.user-info {
-			float: right;
-			width: auto;
-			height: auto;
-			margin-left: 0.2rem;
-			border-radius: 0.55rem;
-			padding-left: 0.2rem;
-			padding-right: 0.3rem;
-			margin-right: -0.3rem;
-			text-align: right;
-
-			.user-info-text {
-				float: left;
-				width: auto;
-				height: 100%;
-				color: #ffffff;
-				padding-top: 0.01rem;
-				filter:alpha(Opacity=60);-moz-opacity:0.6;opacity: 0.6;
-
-				.terminal-name {
-					width: 100%;
-					height: .4rem;
-					line-height: .4rem;
-					font-size: 0.48rem;
-				}
-
-				.terminal-id {
-					width: 100%;
-					height: .3rem;
-					margin-top: .1rem;
-					line-height: .3rem;
-					font-size: 0.36rem;
-				}
-			}
-
-			&.fe-focus {
-				border: solid unit(@borderSize, rem) #ffe100;
-				box-shadow: .03rem .03rem unit(0, rem) transparent;
-				z-index: 9999;
-				.user-info-icon {
-					width: .9rem;
-				}
-			}
-		}
-	}
-
-	.m-main {
-		width: 100%;
-		height: 8.6rem;
-		margin-top: 0.3rem;
-		padding: .2rem 0rem .3rem 0rem;
-		overflow-y: hidden;
-
-		.scroll-list {
-			width: 100%;
-			padding-bottom: 0.5rem;
-
-			.history-wrapper {
-				font-size: 0;
-				width: 100%;
-				height: 4.98rem;
-				padding: 0.2rem 0.09rem 0.2rem;
-				overflow: hidden;
-
-				.history-item {
-					display: inline-block;
-					width: 20%;
-					height: 100%;
-					padding: 0 .06rem;
-
-					.course-item-frame {
-						color: #303030;
-						.course-item-frame;
-					}
-
-					&.fe-focus .course-item-frame {
-						.after-focus(@borderSize; #ffe100);
-					}
-				}
-			}
-
-			.fun-wrapper {
-				width: 100%;
-				height: 1.8rem;
-				padding: 0 0.09rem;
-				margin-top: .02rem;
-				margin-bottom: .65rem;
-				font-size: 0;
-
-				.fun-item {
-					display: inline-block;
-					width: 20%;
-					height: 1.8rem + 2 * unit(@borderSize, rem);
-					padding: 0 0.11rem - unit(@borderSize, rem);
-
-					img {
-						margin-left: .22rem;
-						height: 1.8rem;
-						width: 3.1rem;
-						border: solid unit(@borderSize, rem) transparent;
-						border-radius: 0.24rem;
-						&:first-child {
-							margin-left: 0;
-						}
-						&.fe-focus {
-							.after-focus(@borderSize; #ffe100);
-						}
-					}
-
-					&.fe-focus img {
-						.after-focus(@borderSize; #ffe100);
-					}
-				}
-			}
-		}
-	}
-}

+ 2 - 2
src/stage/index/style/Mixins.less

@@ -23,8 +23,8 @@
 }
 
 .after-focus(@borderSize:0; @borderColor: transparent; @boxShadowSize: 0; @boxShadowColor: transparent) {
-	transform: scale3d(1.07, 1.07, 1.07);
-	-webkit-transform: scale3d(1.07, 1.07, 1.07);
+	transform: scale3d(1.03, 1.03, 1.03);
+	-webkit-transform: scale3d(1.03, 1.03, 1.03);
 	border: solid unit(@borderSize, rem) @borderColor;
 	box-shadow: .03rem .03rem unit(@boxShadowSize, rem) @boxShadowColor;
 	z-index: 9999;

+ 84 - 0
src/stage/index/style/RelatedPKGScene.less

@@ -0,0 +1,84 @@
+#RelatedPKGScene {
+	position: absolute;
+	width: 100%;
+	height: 100%;
+
+	.related-pkg-bg {
+		position: absolute;
+		top: 0;
+		left: 0;
+		z-index: -1;
+		width: 100%;
+		height: 100%;
+		img {
+			position: absolute;
+			top: 0;
+			left: 0;
+			width: 100%;
+			height: 100%;
+		}
+	}
+
+    .icon-close {
+        position: absolute;
+        top: .49rem;
+        right: .64rem;
+        width: .77rem + 2 * unit(@borderSize, rem);
+        height: .77rem + 2 * unit(@borderSize, rem);
+        border: solid unit(@borderSize, rem) transparent;
+        img {
+            width: .77rem;
+            height: .77rem;
+        }
+        &.fe-focus {
+            border: solid unit(@borderSize, rem) #ff5050;
+            border-radius: 100%;
+        }
+    }
+
+	.related-pkg-wrapper {
+        position: absolute;
+        top: .82rem;
+        left: 4rem;
+        width: 11.2rem;
+        height: 7.12rem;
+        padding: 1rem;
+        .course-name-wrapper {
+            height: .38rem;
+            line-height: .38rem;
+            vertical-align: middle;
+            text-align: left;
+            font-size: .38rem;
+            color: #fff;
+            .course-name {
+                color: yellow;
+            }
+        }
+        .related-pkg {
+            width: 100%;
+            height: 5.62rem;
+            margin-top: .95rem;
+            overflow: hidden;
+            .scroll-list {
+                width: 100%;
+                .related-pkg-item {
+                    width: 9.2rem;
+                    height: 1rem;
+                    line-height: 1rem;
+                    vertical-align: middle;
+                    background: #fff;
+                    border-radius: .24rem;
+                    margin-bottom: .13rem;
+                    font-size: .38rem;
+                    border: solid unit(@borderSize, rem) transparent;
+                    &.fe-focus {
+                        border: solid unit(@borderSize, rem) #ff5050;
+                    }
+                    .related-pkg-name {
+                        float: left;
+                    }
+                }
+            }
+        }
+    }
+}

+ 86 - 0
src/stage/index/style/RenewAlertScene.less

@@ -0,0 +1,86 @@
+#RenewAlertScene {
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 100%;
+	background-color: rgba(0, 0, 0, .8);
+	z-index: 2;
+    .icon-close {
+        position: absolute;
+        top: 1.34rem;
+        right: 3.55rem;
+        width: .77rem + 2 * unit(@borderSize, rem);
+        height: .77rem + 2 * unit(@borderSize, rem);
+        border: solid unit(@borderSize, rem) transparent;
+        img {
+            width: .77rem;
+            height: .77rem;
+        }
+        &.fe-focus {
+        	border: solid unit(@borderSize, rem) #ff5050;
+        	border-radius: 100%;
+        }
+    }
+	.renew-product {
+		position: absolute;
+		top: 2.48rem;
+		left: 5rem;
+		width: 9.2rem;
+		height: 5.52rem;
+		overflow: hidden;
+		.scroll-list {
+			width: 100%;
+			.renew-item {
+				width: 9.2rem;
+				height: 1rem;
+				line-height: 1rem;
+				vertical-align: middle;
+				overflow-x: hidden;
+				background: #fff;
+				border-radius: .24rem;
+				margin-bottom: .13rem;
+				font-size: .38rem;
+				.renew-item-name {
+					float: left;
+					max-width: 4.5rem;
+					white-space: nowrap;
+					overflow: hidden;
+					text-overflow: ellipsis;
+				}
+				.renew-item-type {
+					float: left;
+				}
+				.renew-item-expire {
+					float: right;
+					.renew-item-expire-day {
+						color: red;
+					}
+				}
+				.renew-item-btn {
+					display: block;
+					// 垂直居中
+					position: relative;
+					top: 50%;
+					transform: translateY(-50%);
+					// 向右浮动
+					float: right;
+					text-align: center;
+					// 文字垂直居中
+					width: 1.3rem;
+					height: .65rem;
+					line-height: .7rem;
+					vertical-align: middle;
+					// 设置左右margin
+					margin: 0 .15rem;
+					background: #ffc503;
+					border-radius: .2rem;
+					border: solid unit(@borderSize, rem) transparent;
+					&.fe-focus {
+						border: solid unit(@borderSize, rem) #ff5050;
+					}
+				}
+			}
+		}
+	}
+}

+ 153 - 0
src/stage/index/style/ScanToPayScene.less

@@ -0,0 +1,153 @@
+#ScanToPayScene {
+	position: absolute;
+	width: 100%;
+	height: 100%;
+	.pay-bg {
+		position: absolute;
+		top: 0;
+		left: 0;
+		z-index: -1;
+		width: 100%;
+		height: 100%;
+		img {
+			position: absolute;
+			top: 0;
+			left: 0;
+			width: 100%;
+			height: 100%;
+		}
+	}
+
+    .pay-content {
+        position: absolute;
+        top: .75rem;
+        left: 2.42rem;
+        width: 14.25rem;
+        height: 8.47rem;
+
+        .pkg-title {
+            height: .65rem;
+            line-height: .65rem;
+            width: 100%;
+            font-size: .36rem;
+            color: yellow;
+        }
+
+        .pkg-content {
+            width: 100%;
+            height: 1.27rem;
+            margin-top: .15rem;
+            padding-left: .15rem;
+            line-height: .6rem;
+            vertical-align: middle;
+            /* 背景渐变透明 */
+            background: -moz-linear-gradien(360deg, rgba(255, 255, 255, .1) 5%, rgba(255, 255, 255, 0.02) 85%, rgba(255, 255, 255, 0) 95%);
+            background: -webkit-linear-gradient(360deg, rgba(255, 255, 255, .1) 5%, rgba(255, 255, 255, 0.02) 85%, rgba(255, 255, 255, 0) 95%);
+            background: -o-linear-gradient(360deg, rgba(255, 255, 255, .1) 5%, rgba(255, 255, 255, 0.02) 85%, rgba(255, 255, 255, 0) 95%);
+            background: -ms-linear-gradient(360deg, rgba(255, 255, 255, .1) 5%, rgba(255, 255, 255, 0.02) 85%, rgba(255, 255, 255, 0) 95%);
+            background: linear-gradient(90deg, rgba(255, 255, 255, .1) 5%, rgba(255, 255, 255, 0.02) 85%, rgba(255, 255, 255, 0) 95%);
+            .course-item {
+                color: #fff;
+                font-size: .26rem;
+                width: 25%;
+                float: left;
+                overflow: hidden;
+                text-overflow: ellipsis;
+                white-space: nowrap;
+            }
+        }
+
+        .pkg-goods {
+            float: left;
+            width: 8.7rem;
+            height: 6.1rem;
+            padding: 0 .12rem;
+            margin-top: .17rem;
+            overflow: hidden;
+            .scroll-list {
+                width: 100%;
+                .goods-item {
+                    width: 8.47rem;
+                    height: 1.1rem;
+                    margin-bottom: .15rem;
+                    position: relative;
+                    /* 超值推荐 */
+                    .goods-item-recommend {
+                        position: absolute;
+                        top: .05rem;
+                        left: .1rem;
+                        font-size: .2rem;
+                        color: red;
+                    }
+                    /* 光标指向此处,更改背景样式 */
+                    &.fe-focus {
+                        background-image: url('assets/img/ScanToPayScene/goods_selected.png');
+                        background-repeat: no-repeat;
+                        background-size: contain;
+                        .goods-item-wrapper {
+                            background-color: inherit;
+                            width: 8.47rem;
+                            height: 1.1rem;
+                            padding: 0 1.09rem 0 .5rem;
+                        }
+                    }
+                    .goods-item-wrapper {
+                        width: 7.88rem;
+                        height: 1.1rem;
+                        line-height: 1.1rem;
+                        vertical-align: middle;
+                        padding: 0 .5rem;
+                        background-color: #fff;
+                    }
+                    /* 设置价格样式 */
+                    .goods-price-terminal {
+                        font-size: .38rem;
+                        font-weight: bold;
+                        float: left;
+                    }
+                    .goods-price-original {
+                        float: right;
+                        margin-right: .3rem;
+                        color: #b2b2b2;
+                        font-size: .26rem;
+                        text-decoration: line-through;
+                    }
+                    .goods-price-adjust {
+                        font-size: .3rem;
+                        color: #adadad;
+                        float: right;
+                    }
+                }
+            }
+        }
+
+        .shop-qr {
+            float: left;
+            width: 5.4rem;
+            height: 6.1rem;
+            margin-top: .17rem;
+            background: linear-gradient(135deg, transparent 15px, #fff 0);
+            .shop-qr-img {
+                width: 5rem;
+                height: 5rem;
+                margin: .2rem;
+                img {
+                    width: 100%;
+                    height: 100%;
+                }
+            }
+            .shop-qr-desc {
+                width: 100%;
+                height: .67rem;
+                line-height: .67rem;
+                vertical-align: middle;
+                text-align: center;
+                font-size: .36rem;
+                border-top: solid unit(.03, rem) #381b75;
+                span {
+                    color: #e8561a;
+                }
+            }
+        }
+    }
+}

+ 212 - 32
src/stage/index/style/TerminalScene.less

@@ -2,10 +2,8 @@
 	position: absolute;
 	width: 100%;
 	height: 100%;
-	padding: 0 3.76rem;
-    background-size: cover;
 
-	.terminal-bg {
+	.background {
 		position: absolute;
 		top: 0;
 		left: 0;
@@ -21,41 +19,223 @@
 		}
 	}
 
-	.terminal-wrapper {
-		margin-top: 2.78rem;
-
-		.info-item {
-			width: 100%;
+	.terminal {
+		position: absolute;
+		top: 2.21rem;
+		left: 1.6rem;
+		width: 5.72rem;
+		height: 6.35rem;
+		background: #feffec;
+		border-radius: .7rem;
+		.semi-circle {
+			width: 1.38rem;
+			height: 1.38rem;
+			margin-top: -0.69rem;
+			margin-left: 2.17rem;
+			background: #feffec;
+			border-radius: 100%;
+			img {
+				width: .85rem;
+				height: .66rem;
+				display: block;
+				position: relative;
+				top: 50%;
+				left: 50%;
+				transform: translate(-50%, -50%);
+			}
+		}
+		.info-content {
+			display: block;
+			margin-top: .1rem;
+			.info-item {
+				width: 5.13rem;
+				height: .6rem;
+				margin-left: .59rem;
+				margin-bottom: .2rem;
+				overflow: hidden;
+				text-overflow: ellipsis;
+				white-space: nowrap;
+				font-size: .32rem;
+				color: #051841;
+				div {
+					display: inline-block;
+					height: 100%;
+					width: 1.3rem;
+					text-align: justify;
+					text-justify: distribute-all-lines;/*ie6-8*/
+					text-align-last: justify;/* ie9*/
+					-moz-text-align-last: justify;/*ff*/
+					-webkit-text-align-last: justify;/*chrome 20+*/
+				}
+			}
+		}
+		.quit-account {
+			top: 0;
+			left: 0;
+			margin: 0 auto;
+			width: 2.25rem;
 			height: .7rem;
-			margin-bottom: .5rem;
+			line-height: .6rem;
+			vertical-align: middle;
+			text-align: center;
+			font-size: .36rem;
+			color: #fff;
+			border-radius: .3rem;
+			background: #1b7ac9;
+			margin-top: .6rem;
+			margin-bottom: .43rem;
+			border: solid unit(@borderSize, rem) transparent;
+			&.fe-focus {
+				// .after-focus(@borderSize, #ffe100);
+				border: solid unit(@borderSize, rem) #ffe100;
+			}
+		}
+	}
+	.purchased {
+		position: absolute;
+		top: 1.57rem;
+		right: 1.88rem;
+		width: 9.85rem;
+		height: 6.99rem;
+		background: #fff;
+		border-radius: .6rem;
+		.title {
+			width: 100%;
+			height: .6rem;
+			margin-top: .2rem;
+			margin-left: .5rem;
+			.icon-shopcart {
+				float: left;
+				width: .69rem;
+				height: .57rem;
+				img {
+					width: 100%;
+					height: 100%;
+				}
+			}
+			.text-description {
+				float: left;
+				margin-left: .05rem;
+				height: .57rem;
+				vertical-align: top;
+				font-size: .34rem;
+			}
+		}
+		.back-table {
+			z-index: 0;
+			position: absolute;
+			height: 5.6rem;
+			width: 100%;
+			padding: 0 .59rem;
+			margin-top: .2rem;
+			.back-row {
+				display: table-row;
+				height: .8rem;
+				width: 100%;
+				div {
+					display: table-cell;
+					vertical-align: middle;
+					font-size: .32rem;
+					border-top: solid unit(@borderSize, rem) #f0ecfe;
+				}
+				&.table-header {
+					div {
+						border-top: unset;
+						color: #a1a4af;
+					}
+				}
+				.first-cell {
+					width: 3.09rem;
+					text-align: left;
+				}
+				.second-cell {
+					width: 2.79rem;
+					text-align: left;
+				}
+				.third-cell {
+					width: 2.79rem;
+					text-align: left;
+				}
+			}
+		}
+		.table-content {
+			position: absolute;
+			padding: 0 .59rem;
+			height: 4.8rem;
+			width: 100%;
+			margin-top: 1rem;
 			overflow: hidden;
-			font-size: .46rem;
-			color: #051841;
-			div {
-				display: inline-block;
-				width: 2rem;
-				height: 100%;
-				text-align:justify;
-                text-justify:distribute-all-lines;/*ie6-8*/
-                text-align-last:justify;/* ie9*/
-                -moz-text-align-last:justify;/*ff*/
-                -webkit-text-align-last:justify;/*chrome 20+*/
+			z-index: 1;
+			.scroll-list {
+				width: 100%;
+				.front-row {
+					display: table-row;
+					height: .8rem;
+					width: 100%;
+					&.fe-focus {
+						.first-cell {
+							border: solid unit(@borderSize, rem) #ffe100;
+							border-right: none;
+						}
+						.second-cell {
+							border: solid unit(@borderSize, rem) #ffe100;
+							border-left: none;
+							border-right: none;
+						}
+						.third-cell {
+							border: solid unit(@borderSize, rem) #ffe100;
+							border-left: none;
+						}
+					}
+					&.fe-focus + div {
+						.first-cell {
+							border-top: solid unit(@borderSize, rem) transparent;
+						}
+						.second-cell {
+							border-top: solid unit(@borderSize, rem) transparent;
+						}
+						.third-cell {
+							border-top: solid unit(@borderSize, rem) transparent;
+						}
+					}
+					div {
+						display: table-cell;
+						vertical-align: middle;
+						font-size: .34rem;
+						border-top: solid unit(@borderSize, rem) #f0ecfe;
+					}
+					.first-cell {
+						width: 3.09rem;
+						text-align: left;
+					}
+					.second-cell {
+						width: 2.79rem;
+						text-align: left;
+					}
+					.third-cell {
+						width: 2.79rem;
+						text-align: left;
+					}
+				}
 			}
 		}
 	}
-
-	.terminal-quit {
+	/* 退出界面提示 */
+	.back-message {
 		position: absolute;
-		top: 2.7rem;
-		right: 3.5rem;
-		width: 2rem;
-		height: .65rem;
-		background: url('assets/img/TerminalScene/quit.png') no-repeat center;
-		background-size: 100%;
-		border-radius: .3rem;
-
-		&.fe-focus {
-			.after-focus(@borderSize; #ffe100);
+		right: .3rem;
+		bottom: .2rem;
+		font-size: .24rem;
+		color: #fff;
+		span {
+			display: inline-block;
+			height: .3rem;
+			line-height: .3rem;
+			padding: 0 0.1rem;
+			margin: 0 .1rem;
+			background: #fff;
+			border-radius: .24rem;
+			color: #294973;
 		}
 	}
 }

+ 223 - 0
src/stage/index/style/WaterfallIndexScene.less

@@ -0,0 +1,223 @@
+@import './component/CourseItem.less';
+
+#WaterfallIndexScene {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+  /* 背景图片 */
+  .background {
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: -1;
+    width: 100%;
+    height: 100%;
+    img {
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+    }
+  }
+  /* 顶部工具条样式 */
+  .header {
+    width: 100%;
+    height: 1.39rem;
+    padding: 0 1.41rem;
+    .logo {
+      float: left;
+      margin-top: .23rem;
+      margin-left: -0.2rem;
+      width: 2.34rem;
+      height: 1.05rem;
+      img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+    .clock {
+      width: 2.6rem;
+      position: absolute;
+      left: 8.3rem;
+      top: .2rem;
+      text-align: center;
+      color: #fff;
+      letter-spacing: .02rem;
+      font-size: .78rem;
+      font-weight: 200;
+      font-family: sans-serif, 'Microsoft Yahei', '微软雅黑', Arial;
+      opacity: .9;
+    }
+    .wifi,
+    .system-config {
+      float: right;
+      width: .9rem;
+      height: .9rem;
+      margin-top: .23rem;
+      margin-left: .15rem;
+      border-radius: .45rem;
+			border: solid unit(@borderSize, rem) transparent;
+      img {
+        width: .8rem;
+        height: .8rem;
+      }
+			&.fe-focus {
+				.after-focus(@borderSize; #ffe100);
+			}
+    }
+  }
+  /* 入口及轮播图样式 */
+  .content {
+    width: 100%;
+    height: 8.8rem;
+    padding: 0 1.3rem;
+    /* 左右两侧入口浮动布局,尺寸固定 */
+    .left,
+    .right {
+      float: left;
+      width: 3.1rem + .12rem + 2 * unit(@borderSize, rem);
+      height: 3.9rem + 2 * unit(@borderSize, rem);
+      padding: 0 .06rem;
+      .entrance {
+        width: 3.1rem + 2 * unit(@borderSize, rem);
+        height: 1.84rem + 2 * unit(@borderSize, rem);
+        img {
+          width: 3.1rem;
+          height: 1.84rem;
+					border: solid unit(@borderSize, rem) transparent;
+          border-radius: .25rem;
+        }
+        &:last-child {
+          margin-top: .22rem - 2 * unit(@borderSize, rem);
+        }
+				&.fe-focus img {
+					.after-focus(@borderSize; #ffe100);
+				}
+      }
+    }
+    /* 中间轮播图左侧浮动,尺寸固定 */
+    .center {
+      float: left;
+      min-width: 9.84rem;
+      min-height: 4rem;
+      .swiper-container-advert {
+        position: relative;
+        overflow: hidden;
+        margin: 0 .22rem - .06rem - 2 * unit(@borderSize, rem);
+        width: 9.74rem + 2 * unit(@borderSize, rem);
+        height: 3.9rem + 2 * unit(@borderSize, rem);
+				border: solid unit(@borderSize, rem) transparent;
+        border-radius: .25rem;
+        &.fe-focus {
+					.after-focus(@borderSize; #ffe100);
+        }
+        .swiper-wrapper {
+          width: 9.74rem;
+          height: 3.9rem;
+          .swiper-slide {
+            img {
+              width: 100%;
+              height: 100%;
+            }
+          }
+        }
+      }
+    }
+    /* 推荐位课程列表样式 */
+    .bottom {
+      width: 100%;
+      clear: both;
+      margin-top: .22rem - .1rem - 2 * unit(@borderSize, rem);
+      .recommend-wrapper {
+        font-size: 0;
+        width: 100%;
+        height: 4.78rem;
+        padding: .1rem 0 .1rem 0;
+        .product-item {
+          display: inline-block;
+          width: 20%;
+          height: 100%;
+          padding: 0 .06rem;
+  				.course-item-frame {
+  					color: #303030;
+  					.course-item-frame;
+  				}
+          &.fe-focus .course-item-frame {
+            .after-focus(@borderSize; #ffe100);
+          }
+        }
+      }
+    }
+  }
+  /* 瀑布流内容样式 */
+  .waterfall-content {
+    width: 100%;
+    height: 100%;
+    padding-top: .36rem;
+    .group-wrapper {
+      width: 100%;
+      height: 100%;
+      padding: 0 1.3rem;
+      .group-name {
+        width: 100%;
+        height: .63rem;
+        line-height: .63rem;
+        padding-left: .11rem;
+        color: #fff;
+        font-size: .38rem;
+        font-weight: bold;
+      }
+      .group-list {
+        width: 100%;
+        height: 4.72rem;
+        font-size: 0;
+        padding: .06rem 0 .06rem 0;
+        .product-item {
+          display: inline-block;
+          width: 20%;
+          height: 100%;
+          padding: 0 .06rem;
+          .course-item-frame {
+            color: #303030;
+			.course-item-frame;
+          }
+          &.fe-focus .course-item-frame {
+            .after-focus(@borderSize; #ffe100);
+          }
+        }
+      }
+    }
+  }
+  /* 瀑布流的分页样式 */
+  .swiper-pagination-waterfall {
+    right: .52rem;
+    .swiper-pagination-bullet {
+      margin: 7px auto;
+      width: .15rem;
+      height: .15rem;
+      background-color: #d5d5d5;
+      opacity: .38;
+    }
+    .swiper-pagination-bullet-active {
+      width: .22rem;
+      height: .22rem;
+      background-color: #f8f8ff;
+      opacity: .7;
+    }
+  }
+  /* 向下箭头样式 */
+  .arrow_down {
+    z-index: -1;
+    position: absolute;
+    left: 50%;
+    bottom: .2rem;
+    width: .36rem;
+    height: .21rem;
+    img {
+      width: 100%;
+      height: 100%;
+    }
+  }
+}

+ 33 - 3
src/util/API/APIClient.js

@@ -69,9 +69,9 @@ class APIClient {
 	// 获取标签组下的标签列表
 	static getTagListByGroupCode(type, callback) {
 		const typeToCode = {
-			'RESOURCE': 'BABY_RESOURCE',
-			'TRAINING': 'BABY_TRAINING',
-			'PERIPHERY': 'BABY_SUPPORT',
+			'RESOURCE': 'TALENKID_RESOURCE',
+			'TRAINING': 'TALENKID_TRAINING',
+			'PERIPHERY': 'TALENKID_SUPPORT',
 		};
 		let params = APIClient.addCacheParam({});
 		AJAXHelper.get(`/tagGroup/${typeToCode[type]}`, params, callback);
@@ -83,6 +83,36 @@ class APIClient {
 		params = APIClient.addCacheParam(params);
 		AJAXHelper.get(`/tag/${tagId}`, params, callback);
 	}
+	
+	// 获取推荐海报列表
+	static getRecommendPosters(callback) {
+		let params = APIClient.addCacheParam({});
+		AJAXHelper.get('/recommend/posters', params, callback);
+	}
+
+	// 获取瀑布流内数据
+	static getWaterfallList(callback) {
+		let params = APIClient.addCacheParam({});
+		AJAXHelper.get('/tagType/INDEX_WATERFALL', params, callback);
+	}
+
+	// 获取待续费产品列表
+	static getRenewProductList(callback) {
+		let params = APIClient.addCacheParam({});
+		AJAXHelper.get('/user/message/productExpiredAlert', params, callback);
+	}
+
+	// 获取还未过期产品列表
+	static getValidProductList(callback) {
+		let params = APIClient.addCacheParam({});
+		AJAXHelper.get('/user/product/valid', params, callback);
+	}
+
+	// 根据courseId获取相关的课程包列表
+	static getRelatedPackageList(productId, callback) {
+		let params = APIClient.addCacheParam({ productId });
+		AJAXHelper.get(`/product/${productId}/relatedPkg`, params, callback);
+	}
 
 	// 根据课程获取课列表
 	static getLessonList(courseId, callback) {

+ 13 - 17
src/util/course.js

@@ -164,16 +164,9 @@ class Course {
 		} else {
 			duration = `<p class="use-duration" id="use-duration">${digest || ''}</p>`;
 		}
-		let btnContainer = [];
-		for (let i in goods) {
-			// 这里限制只选择goods列表里的前三个
-			if (i >= 3) break;
-			btnContainer.push(this.generateBuyButton(i, goods[i]));
-		}
 
-		btn = `<div class="btn-panel">${btnContainer.join('')}</div>`;
 		const desc_wrapper = `<div class="desc-wrapper">${duration + desc + buyedIcon}</div>`;
-		main.innerHTML = `<div class="detail-container" id="course-main-detail">${desc_wrapper + btn}</div>`;
+		main.innerHTML = `<div class="detail-container" id="course-main-detail">${desc_wrapper}</div>`;
 	}
 
 	static renderPeriphery(dataset) {
@@ -212,11 +205,11 @@ class Course {
 		const { id, title, subTitle, detail, goods } = data;
 		let price = 0;
 		let goodsId;
-		let isInCart;
+		let shopQR;
 		if (goods && goods.length >= 1) {
 			price = goods[0].terminalPrice;
 			goodsId = goods[0].id;
-			isInCart = goods[0].isInCart;
+			shopQR = goods[0].shopQR;
 		}
 		let main = document.getElementById('course-main');
 		let _detailContent = document.querySelector('#periphery-detail-content');
@@ -228,12 +221,7 @@ class Course {
 		detailContent.setAttribute('id', 'periphery-detail-content');
 		detailContent.setAttribute('fe-role', 'Switch');
 
-		let icon = '';
-		if (isInCart) {
-			icon = '<div fe-role="Widget" class="periphery-icon added" id="periphery-add-cart"></div>';
-		} else {
-			icon = `<div fe-role="Widget" class="periphery-icon add-cart" id="periphery-add-cart" data-goodsId="${goodsId}"></div>`;
-		}
+		let shopQRImg = shopQR ? `<img src="${IMG_PATH}/${shopQR}" alt="" />` : '';
 		let list = '';
 		list = `
 			<div id="periphery-detail-wrapper-${id}" class="periphery-detail-wrapper">
@@ -244,7 +232,15 @@ class Course {
 					<p class="periphery-name">${title + '&nbsp;&nbsp;' + subTitle}</p>
 					<p class="periphery-price">¥${Utils.twoDecimal_f(price)}</p>
 					<p class="periphery-desc">${detail || ''}</p>
-					${icon}
+				</div>
+				<div class="periphery-shopqr">
+					<div class="periphery-shopqr-wrapper">
+						<div class="shopqr-desc">
+							<div class="shopqr-desc-big">微信扫描二维码</div>
+							<div class="shopqr-desc-sub">进入微商城进行购买</div>
+						</div>
+						<div class="shopqr-img">${shopQRImg}</div>
+					</div>
 				</div>
 			</div>`;