Selaa lähdekoodia

feat:新增课程小节试听

zhubo 1 vuosi sitten
vanhempi
commit
4921671494

+ 1 - 1
.eslintrc.js

@@ -18,6 +18,6 @@ module.exports = {
     'no-empty-function': 'off',
     '@typescript-eslint/no-empty-function': ['off'],
     '@typescript-eslint/explicit-module-boundary-types': 'off',
-    "no-non-null-assertion": true
+    'no-non-null-assertion': 0
   }
 }

+ 3 - 1
README.md

@@ -3,7 +3,9 @@
 
 
 ## 访问url
-  https://luojigou.vip/app_web/learn-plan.html#/blue-light-tip 学习计划
+  https://zaojiao.net/app_web/learn-plan.html#/blue-light-tip 学习计划
+
+  https://zaojiao.net/app_web/section-audition.html#/et1WkdUu7ILvQFK 课程小节试听
 
 ## NODE 版本
   14.19.0

+ 1 - 0
components.d.ts

@@ -11,6 +11,7 @@ declare module '@vue/runtime-core' {
     OpenApp: typeof import('./src/components/OpenApp/index.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']
+    VanOverlay: typeof import('vant/es')['Overlay']
     VanProgress: typeof import('vant/es')['Progress']
   }
 }

+ 159 - 161
package-lock.json

@@ -1077,6 +1077,123 @@
         "tslint": "^5.20.1",
         "webpack": "^4.0.0",
         "yorkie": "^2.0.0"
+      },
+      "dependencies": {
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "cosmiconfig": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
+          "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "@types/parse-json": "^4.0.0",
+            "import-fresh": "^3.1.0",
+            "parse-json": "^5.0.0",
+            "path-type": "^4.0.0",
+            "yaml": "^1.7.2"
+          }
+        },
+        "deepmerge": {
+          "version": "4.3.1",
+          "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+          "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+          "dev": true,
+          "optional": true
+        },
+        "fork-ts-checker-webpack-plugin-v5": {
+          "version": "npm:fork-ts-checker-webpack-plugin@5.2.1",
+          "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz",
+          "integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "@babel/code-frame": "^7.8.3",
+            "@types/json-schema": "^7.0.5",
+            "chalk": "^4.1.0",
+            "cosmiconfig": "^6.0.0",
+            "deepmerge": "^4.2.2",
+            "fs-extra": "^9.0.0",
+            "memfs": "^3.1.2",
+            "minimatch": "^3.0.4",
+            "schema-utils": "2.7.0",
+            "semver": "^7.3.2",
+            "tapable": "^1.0.0"
+          }
+        },
+        "fs-extra": {
+          "version": "9.1.0",
+          "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+          "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "at-least-node": "^1.0.0",
+            "graceful-fs": "^4.2.0",
+            "jsonfile": "^6.0.1",
+            "universalify": "^2.0.0"
+          }
+        },
+        "jsonfile": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+          "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "graceful-fs": "^4.1.6",
+            "universalify": "^2.0.0"
+          }
+        },
+        "lru-cache": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+          "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "yallist": "^4.0.0"
+          }
+        },
+        "schema-utils": {
+          "version": "2.7.0",
+          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz",
+          "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "@types/json-schema": "^7.0.4",
+            "ajv": "^6.12.2",
+            "ajv-keywords": "^3.4.1"
+          }
+        },
+        "semver": {
+          "version": "7.5.4",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+          "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "universalify": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+          "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+          "dev": true,
+          "optional": true
+        }
       }
     },
     "@vue/cli-plugin-vuex": {
@@ -1149,6 +1266,17 @@
         "webpack-merge": "^4.2.2"
       },
       "dependencies": {
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
         "cliui": {
           "version": "6.0.0",
           "resolved": "https://registry.npmmirror.com/cliui/-/cliui-6.0.0.tgz",
@@ -1160,6 +1288,37 @@
             "wrap-ansi": "^6.2.0"
           }
         },
+        "json5": {
+          "version": "2.2.3",
+          "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+          "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+          "dev": true,
+          "optional": true
+        },
+        "loader-utils": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
+          "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "big.js": "^5.2.2",
+            "emojis-list": "^3.0.0",
+            "json5": "^2.1.2"
+          }
+        },
+        "vue-loader-v16": {
+          "version": "npm:vue-loader@16.8.3",
+          "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
+          "integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "chalk": "^4.1.0",
+            "hash-sum": "^2.0.0",
+            "loader-utils": "^2.0.0"
+          }
+        },
         "wrap-ansi": {
           "version": "6.2.0",
           "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
@@ -5768,123 +5927,6 @@
         }
       }
     },
-    "fork-ts-checker-webpack-plugin-v5": {
-      "version": "npm:fork-ts-checker-webpack-plugin@5.2.1",
-      "resolved": "https://registry.npmmirror.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz",
-      "integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "@babel/code-frame": "^7.8.3",
-        "@types/json-schema": "^7.0.5",
-        "chalk": "^4.1.0",
-        "cosmiconfig": "^6.0.0",
-        "deepmerge": "^4.2.2",
-        "fs-extra": "^9.0.0",
-        "memfs": "^3.1.2",
-        "minimatch": "^3.0.4",
-        "schema-utils": "2.7.0",
-        "semver": "^7.3.2",
-        "tapable": "^1.0.0"
-      },
-      "dependencies": {
-        "chalk": {
-          "version": "4.1.2",
-          "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz",
-          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "cosmiconfig": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
-          "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "@types/parse-json": "^4.0.0",
-            "import-fresh": "^3.1.0",
-            "parse-json": "^5.0.0",
-            "path-type": "^4.0.0",
-            "yaml": "^1.7.2"
-          }
-        },
-        "deepmerge": {
-          "version": "4.3.1",
-          "resolved": "https://registry.npmmirror.com/deepmerge/-/deepmerge-4.3.1.tgz",
-          "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
-          "dev": true,
-          "optional": true
-        },
-        "fs-extra": {
-          "version": "9.1.0",
-          "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-9.1.0.tgz",
-          "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "at-least-node": "^1.0.0",
-            "graceful-fs": "^4.2.0",
-            "jsonfile": "^6.0.1",
-            "universalify": "^2.0.0"
-          }
-        },
-        "jsonfile": {
-          "version": "6.1.0",
-          "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz",
-          "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "graceful-fs": "^4.1.6",
-            "universalify": "^2.0.0"
-          }
-        },
-        "lru-cache": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz",
-          "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "yallist": "^4.0.0"
-          }
-        },
-        "schema-utils": {
-          "version": "2.7.0",
-          "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-2.7.0.tgz",
-          "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "@types/json-schema": "^7.0.4",
-            "ajv": "^6.12.2",
-            "ajv-keywords": "^3.4.1"
-          }
-        },
-        "semver": {
-          "version": "7.4.0",
-          "resolved": "https://registry.npmmirror.com/semver/-/semver-7.4.0.tgz",
-          "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "lru-cache": "^6.0.0"
-          }
-        },
-        "universalify": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.0.tgz",
-          "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
-          "dev": true,
-          "optional": true
-        }
-      }
-    },
     "form-data": {
       "version": "2.3.3",
       "resolved": "https://registry.npmmirror.com/form-data/-/form-data-2.3.3.tgz",
@@ -13284,50 +13326,6 @@
         }
       }
     },
-    "vue-loader-v16": {
-      "version": "npm:vue-loader@16.8.3",
-      "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-16.8.3.tgz",
-      "integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "chalk": "^4.1.0",
-        "hash-sum": "^2.0.0",
-        "loader-utils": "^2.0.0"
-      },
-      "dependencies": {
-        "chalk": {
-          "version": "4.1.2",
-          "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz",
-          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "json5": {
-          "version": "2.2.3",
-          "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz",
-          "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
-          "dev": true,
-          "optional": true
-        },
-        "loader-utils": {
-          "version": "2.0.4",
-          "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.4.tgz",
-          "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^3.0.0",
-            "json5": "^2.1.2"
-          }
-        }
-      }
-    },
     "vue-router": {
       "version": "4.1.6",
       "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.1.6.tgz",

+ 11 - 0
src/api/sectionAudition.ts

@@ -0,0 +1,11 @@
+import request from '@/service'
+
+/**
+ * 获取试听小节
+ */
+export const getTrialAudioRequest = (code: string) => {
+  return request({
+    url: `/app/h5/trialAudio/${code}`,
+    method: 'GET'
+  })
+}

+ 33 - 35
src/components/OpenApp/index.vue

@@ -1,20 +1,20 @@
 <template>
-  <!-- position:absolute;left:0;top:0;width:100%;height:100% -->
   <div class="wx-open-app">
     <wx-open-launch-app
       id="launch-btn"
       ref="launchBtnRef"
-      :appid="state.appid"
-      :extinfo="state.extinfo"
+      :appid="props.appid"
+      :extinfo="props.extinfo"
       @ready="handleReadyFn"
     >
-      <div v-is="'script'" type="text/wxtag-template" >
-        <div
-          class="btn"
+      <div v-is="'script'" type="text/wxtag-template">
+        <slot>
+          <div
+            class="btn"
             style="
             width: 334px;
             height: 52px;
-            background: #FF8024;
+            background: #ff8024;
             border-radius: 26px;
             display: flex;
             justify-content: center;
@@ -22,26 +22,32 @@
             font-size: 18px;
             font-family: PingFangSC-Regular, PingFang SC;
             font-weight: 400;
-            color: #FFFFFF;
+            color: #ffffff;
           "
           >
             打开APP
-        </div>
+          </div>
+        </slot>
       </div>
     </wx-open-launch-app>
   </div>
 </template>
 
-<script lang="ts" setup >
-import { reactive } from 'vue';
-import { ref } from 'vue'
+<script lang="ts" setup>
+import { defineProps, withDefaults, ref } from 'vue'
+
+interface IProps {
+  appid?: string;
+  extinfo?: string;
+}
+
+const props = withDefaults(defineProps<IProps>(), {
+  // wxe87236d542cd0f94 逻辑狗思维教育公众号
+  // wxd61f929a1c72280a 思维魔法学堂公众号
+
+  // wxeb44a864bdd935be zaojiao.net
+  // wxf6e96c65ba6116d4 luojigou.vip
 
-// export interface IProps {
-//   appid?: string
-//   extinfo?: string
-// }
-// wxe87236d542cd0f94 // wxeb44a864bdd935be // wxd61f929a1c72280a
-const state = reactive({
   appid: 'wxeb44a864bdd935be',
   extinfo: ''
 })
@@ -49,24 +55,16 @@ const state = reactive({
 const launchBtnRef = ref()
 
 const handleReadyFn = () => {
+  launchBtnRef.value.addEventListener('launch', function () {
+    console.log('launch')
+  })
 
-    launchBtnRef.value.addEventListener("launch", function () {
-      console.log('launch');
-    });
-
-    launchBtnRef.value.addEventListener("error", function (e: any) {
-      console.log('error:', e.detail);
-      window.location.href = `https://sj.qq.com/myapp/detail.htm?apkName=com.zaojiao.app`;
-    });
-
+  launchBtnRef.value.addEventListener('error', function (e: any) {
+    console.log('error:', e.detail)
+    window.location.href =
+      'https://sj.qq.com/myapp/detail.htm?apkName=com.zaojiao.app'
+  })
 }
-
-
 </script>
- 
-<style  >
-
-
-</style>
-
 
+<style></style>

+ 6 - 0
src/pages/SectionAudition/App.vue

@@ -0,0 +1,6 @@
+<script setup lang="ts">
+</script>
+
+<template>
+  <router-view/>
+</template>

BIN
src/pages/SectionAudition/assets/close.png


BIN
src/pages/SectionAudition/assets/logo.png


BIN
src/pages/SectionAudition/assets/pause.png


BIN
src/pages/SectionAudition/assets/play.png


BIN
src/pages/SectionAudition/assets/remind_logo.png


+ 12 - 0
src/pages/SectionAudition/main.ts

@@ -0,0 +1,12 @@
+import { createApp } from 'vue'
+import App from './App.vue'
+import 'lib-flexible'
+import 'normalize.css'
+import * as Pinia from 'pinia'
+import VConsole from 'vconsole'
+import '@/utils/vant'
+import router from './router'
+
+const vcs = new VConsole()
+
+createApp(App).use(router).use(Pinia.createPinia()).mount('#SectionAudition')

+ 17 - 0
src/pages/SectionAudition/public/index.html

@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title></title>
+  </head>
+  <body>
+    <noscript>
+      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <div id="SectionAudition"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

+ 16 - 0
src/pages/SectionAudition/router/index.ts

@@ -0,0 +1,16 @@
+import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
+
+const routes: Array<RouteRecordRaw> = [
+  {
+    path: '/:id',
+    name: 'index',
+    component: () => import('../views/index.vue')
+  }
+]
+
+const router = createRouter({
+  history: createWebHashHistory(),
+  routes
+})
+
+export default router

+ 638 - 0
src/pages/SectionAudition/views/index.vue

@@ -0,0 +1,638 @@
+<script setup lang="ts">
+import { computed, onMounted, reactive, ref, watch } from 'vue'
+import { useRoute } from 'vue-router'
+import { useAudioManager } from '@/hook'
+import ProgressBar from '@/pages/SectionAudition/components/ProgressBar.vue'
+import { registerWxopenButton } from '@/utils/utils'
+import { getTrialAudioRequest } from '@/api/sectionAudition'
+import dayjs from 'dayjs'
+
+const logo = require('../assets/logo.png')
+const pause = require('../assets/pause.png')
+const play = require('../assets/play.png')
+const remindLogo = require('../assets/remind_logo.png')
+const close = require('../assets/close.png')
+
+const space = 32
+const defaultSection = {
+  id: '',
+  name: '',
+  videoId: null,
+  aiCourseSkuId: '',
+  sort: 0,
+  createTime: '',
+  updateTime: '',
+  readCount: 0,
+  aiCourseItemChapterId: '',
+  type: 1,
+  payType: 0,
+  freeTime: 0,
+  audioId: '',
+  imgCover: '',
+  chapterName: '',
+  chapterSort: 0,
+  richText: null,
+  splitList: null,
+  readCountStr: '',
+  audio: {
+    id: null,
+    audioUrl: '',
+    parentId: null,
+    createTime: null,
+    updateTime: null,
+    duration: ''
+  }
+}
+const defaultCourse = {
+  id: '',
+  name: '',
+  imgCover: '',
+  imgCoverMini: '',
+  createTime: '',
+  updateTime: '',
+  price: 0,
+  markingPrice: 0,
+  categoryId: '',
+  courseCount: 0,
+  aiCourseSpuId: '',
+  suitAge: '',
+  wxNumber: null,
+  wxQrCode: null,
+  wxName: null,
+  wxHeadImg: null,
+  description: '',
+  mediaType: 1,
+  simpleDescription: '',
+  sort: 0,
+  showChapter: 1,
+  courseType: 0,
+  subCategoryId: '',
+  activityTag: null,
+  courseTags: [],
+  paidCount: 0,
+  latestLearnedRecordId: null,
+  latestLearnedRecord: null,
+  abilityList: null,
+  commentCount: null,
+  shareCount: null,
+  collectCount: null,
+  isCollect: 0,
+  hasPaid: 0,
+  isComment: null,
+  isShare: null,
+  imgCoverWidth: null,
+  imgCoverHeight: null,
+  shareUrl: '',
+  shareUrlQRCode: null,
+  groupBuyActivity: null,
+  groupBuyActivityId: null,
+  groupBuyActivityUrl: null,
+  totalLearnUser: 0,
+  cashbackActivity: 0,
+  cashbackActivityId: null,
+  textbook: null,
+  checkInExplain: null,
+  chapterList: [
+    {
+      id: '',
+      name: '',
+      createTime: '',
+      updateTime: null,
+      aiCourseSkuId: '',
+      sort: 0,
+      coverImgUrl: '',
+      itemList: [
+        {
+          id: '',
+          name: '',
+          videoId: null,
+          aiCourseSkuId: '',
+          sort: 0,
+          createTime: '',
+          updateTime: '',
+          readCount: 0,
+          aiCourseItemChapterId: '',
+          type: 1,
+          payType: 0,
+          freeTime: 0,
+          audioId: '',
+          imgCover: '',
+          chapterName: '',
+          chapterSort: 0,
+          richText: null,
+          splitList: null,
+          readCountStr: '',
+          audio: {
+            id: null,
+            audioUrl: null,
+            parentId: null,
+            createTime: null,
+            updateTime: null,
+            duration: ''
+          }
+        }
+      ]
+    }
+  ],
+  spu: {
+    id: '',
+    name: '',
+    imgCover: '',
+    imgCoverMini: '',
+    videoUrl: '',
+    createTime: '',
+    updateTime: '',
+    price: 0,
+    markingPrice: 0,
+    categoryId: '',
+    suitAge: '',
+    parentNotice: null,
+    courseCount: 0,
+    description: null,
+    outline: null,
+    notice: null,
+    simpleDescription: '',
+    mediaType: 1,
+    status: 1,
+    isDelete: 0,
+    sort: 0,
+    showChapter: 1,
+    isShow: true,
+    showCoverImg: 1
+  },
+  showCoverImg: 1,
+  position: 0,
+  trialLearn: 0
+}
+
+const { id } = useRoute().params
+
+const [fco, atx] = useAudioManager({
+  url: '',
+  format: 'mm:ss'
+})
+
+const course = reactive(defaultCourse)
+const section = reactive(defaultSection)
+const percentage = ref(0)
+const playing = ref(false)
+const show = ref(false)
+const progressRef = ref()
+const progressBarWidth = ref(0)
+
+const maxPercentage = computed(() => {
+  if (section.freeTime && section.audio.duration) {
+    return section.freeTime / Number(section.audio.duration)
+  } else {
+    return 1
+  }
+})
+
+watch(
+  () => fco.percentage,
+  () => {
+    setPercentage(fco.percentage || 0)
+    if (fco.percentage >= maxPercentage.value) {
+      fco.pause()
+      playing.value = false
+      show.value = true
+    }
+  }
+)
+
+watch(
+  () => course.name,
+  () => {
+    console.log(section, 'duration')
+
+    fco.src = section.audio.audioUrl
+    document.title = course.name
+  }
+)
+
+const setPercentage = (num: number) => {
+  if (num > maxPercentage.value) {
+    percentage.value = maxPercentage.value
+  } else if (num < 0) {
+    percentage.value = 0
+  } else {
+    percentage.value = num
+  }
+}
+
+const timeToSeconds = (timeStr: string | number) => {
+  if (typeof timeStr === 'string') {
+    let [minutes, seconds] = timeStr.split(':').map(Number)
+    // console.log(minutes, typeof seconds, 'minutes, seconds')
+    if (minutes === undefined) minutes = 0
+    if (seconds === undefined) seconds = 0
+    return minutes * 60 + seconds
+  } else {
+    return 0
+  }
+}
+
+function secondsToTime (seconds:string) {
+  return dayjs(Math.round(Number(seconds))).format('mm:ss')
+}
+
+function playAudio () {
+  if (!playing.value) {
+    if (fco.percentage >= maxPercentage.value) {
+      fco.setPercentage(0)
+    }
+    fco.play()
+  } else {
+    fco.pause()
+  }
+  playing.value = !playing.value
+}
+
+async function getTrialAudio (id: string) {
+  const { data, status } = await getTrialAudioRequest(id)
+  if (status === 200) {
+    Object.assign(course, data)
+    if (
+      data &&
+      Array.isArray(data.chapterList) &&
+      data.chapterList.length > 0 &&
+      data.chapterList[0].itemList &&
+      data.chapterList[0].itemList.length > 0
+    ) {
+      Object.assign(section, data.chapterList[0].itemList[0], {
+        // freeTime: 10,
+        // audio: {
+        //   id: null,
+        //   audioUrl: 'https://img.luojigou.vip/FiNShd4u8KWEQf09XrjryjfdzR_e',
+        //   parentId: null,
+        //   createTime: null,
+        //   updateTime: null,
+        //   duration: '12'
+        // }
+      })
+      console.log(fco.duration, 'fco.duration')
+      console.log(section.audio.duration, 'section.audio.duration')
+    }
+  }
+}
+
+onMounted(async () => {
+  progressBarWidth.value = progressRef.value.clientWidth - space * 2
+
+  progressRef.value.addEventListener('touchstart', () => {
+    fco.pause()
+    playing.value = false
+  })
+  progressRef.value.addEventListener('touchmove', (event: { touches: { pageX: number }[] }) => {
+    const { pageX } = event.touches[0]
+    if (pageX > space && pageX <= progressBarWidth.value + space) {
+      const num = (pageX - space) / progressBarWidth.value
+      fco.setPercentage(num)
+    }
+  })
+  progressRef.value.addEventListener('touchend', () => {
+    fco.play()
+    playing.value = true
+  })
+  console.log(id, 'id')
+  await getTrialAudio(id as string)
+  await registerWxopenButton()
+})
+</script>
+
+<template>
+  <div class="section-audition sa">
+    <div class="sa-cover" @click="playAudio">
+      <img :src="section.imgCover" alt="" class="sa-cover-img" />
+      <div class="sa-cover-tips">
+        试听剩余{{timeToSeconds(fco.duration) - timeToSeconds(fco.updateTime)}}s,体验完整版前往APP
+      </div>
+      <img :src="playing ? pause : play" alt="" class="sa-cover-btn" />
+    </div>
+    <div class="sa-process">
+      <div class="progress" ref="progressRef">
+        <div
+          class="progress-bar"
+          :style="{ width: `calc(100vw - ${space * 2}px)` }"
+        >
+          <div
+            class="progress-bar-track"
+            :style="{ width: `${maxPercentage * progressBarWidth}px` }"
+          ></div>
+          <div
+            v-if="maxPercentage < 1 && maxPercentage > 0"
+            class="progress-bar-max"
+            :style="{ left: `${maxPercentage * progressBarWidth}px` }"
+          ></div>
+          <div
+            class="progress-bar-pivot"
+            :style="{ left: `${percentage * progressBarWidth}px` }"
+          ></div>
+        </div>
+      </div>
+      <div class="sa-process-time">
+        <div>{{ fco.updateTime || "00:00" }}</div>
+        <div>{{ fco.duration || secondsToTime(section.audio.duration) ||"00:00" }}</div>
+      </div>
+    </div>
+    <div class="sa-title">{{ course.name }}</div>
+    <div class="sa-open">
+      <img :src="logo" alt="logo" class="sa-open-logo" />
+      <div class="sa-open-text">
+        <h4>逻辑狗APP</h4>
+        <div>少儿思维教育,就选逻辑狗</div>
+      </div>
+      <div class="sa-open-btn">
+        <OpenApp>
+          <div
+            style="
+              display: flex;
+              justify-content: center;
+              align-items: center;
+              width: 74px;
+              height: 32px;
+              background: #0b47a4;
+              border-radius: 16px;
+              font-size: 14px;
+              font-family: PingFang SC-Semibold, PingFang SC;
+              font-weight: 600;
+              color: #ffffff;
+            "
+          >
+            打开
+          </div>
+        </OpenApp>
+      </div>
+    </div>
+
+    <VanOverlay :show="show" :z-index="3" @click="show = false">
+      <div class="sa-remind" @click.stop>
+        <img :src="remindLogo" alt="" class="sa-remind-logo" />
+        <img
+          :src="close"
+          alt=""
+          class="sa-remind-close"
+          @click="show = false"
+        />
+        <div class="sa-remind-container">
+          <div class="title">前往APP继续观看</div>
+          <div class="desc">试听已结束,收听完整资源</div>
+          <div class="desc mb12">请前往APP继续</div>
+          <OpenApp>
+            <div
+              style="
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                margin: 0 auto;
+                width: 182px;
+                height: 49px;
+                background: #2654bf;
+                border-radius: 25px 25px 25px 25px;
+                font-size: 18px;
+                font-family: PingFang SC-Medium, PingFang SC;
+                font-weight: 500;
+                color: #ffffff;
+              "
+            >
+              前往APP
+            </div>
+          </OpenApp>
+        </div>
+      </div>
+    </VanOverlay>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.sa {
+  overflow: hidden;
+
+  &-cover {
+    position: relative;
+    margin: 20px auto 0;
+    width: 335px;
+    border-radius: 20px;
+    overflow: hidden;
+
+    &-img {
+      display: block;
+      width: 100%;
+    }
+
+    &-tips {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      position: absolute;
+      right: 16px;
+      top: 16px;
+      width: 226px;
+      height: 24px;
+      background: rgba(0, 0, 0, 0.5);
+      border-radius: 40px;
+      font-size: 13px;
+      font-family: PingFang SC-Regular, PingFang SC;
+      font-weight: 400;
+      color: #ffffff;
+    }
+
+    &-btn {
+      display: block;
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      width: 60px;
+      height: 60px;
+    }
+  }
+
+  &-process {
+    width: 100%;
+
+    .progress {
+      padding: 27px 0;
+      width: 100%;
+
+      &-bar {
+        position: relative;
+        margin: 0 auto;
+        width: calc(100vw - 40px);
+        height: 3px;
+        background-color: #ededed;
+        border-radius: 2px;
+
+        &-track {
+          height: 3px;
+          background-color: #b7d2ff;
+          border-radius: 2px;
+        }
+
+        &-max {
+          position: absolute;
+          top: 50%;
+          left: 0;
+          transform: translate(-50%, -50%);
+          width: 2px;
+          height: 7px;
+          background: #B7D2FF;
+          border-radius: 1px;
+        }
+
+        &-pivot {
+          position: absolute;
+          top: 50%;
+          left: 0;
+          transform: translate(-50%, -50%);
+          z-index: 3;
+          width: 13px;
+          height: 13px;
+          background-color: #0643a2;
+          border-radius: 50%;
+        }
+      }
+    }
+
+    &-time {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding-left: 31px;
+      padding-right: 29px;
+      position: relative;
+      top: -13px;
+      left: 0;
+      z-index: 2;
+      ont-size: 13px;
+      font-family: PingFang SC-Regular, PingFang SC;
+      font-weight: 400;
+      color: #333333;
+      box-sizing: border-box;
+    }
+  }
+
+  &-title {
+    margin-top: 18px;
+    height: 16px;
+    font-size: 18px;
+    font-family: PingFang SC-Semibold, PingFang SC;
+    font-weight: 600;
+    color: #333333;
+    line-height: 16px;
+    text-align: center;
+  }
+
+  &-open {
+    display: flex;
+    align-items: center;
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    width: 100vw;
+    height: 67px;
+    background: #f1f1f1;
+
+    &-logo {
+      display: block;
+      margin-left: 14px;
+      margin-right: 17px;
+      width: 43px;
+      height: 43px;
+    }
+
+    &-text {
+      h4 {
+        margin: 0 0 3px;
+        height: 17px;
+        font-size: 14px;
+        font-family: PingFang SC-Semibold, PingFang SC;
+        font-weight: 600;
+        color: #333333;
+        line-height: 17px;
+      }
+
+      div {
+        height: 14px;
+        font-size: 12px;
+        font-family: PingFang SC-Regular, PingFang SC;
+        font-weight: 400;
+        color: #999999;
+        line-height: 14px;
+      }
+    }
+
+    &-btn {
+      position: absolute;
+      right: 13px;
+      top: 50%;
+      transform: translateY(-50%);
+    }
+  }
+
+  &-remind {
+    position: fixed;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -65%);
+    z-index: 5;
+
+    img {
+      display: block;
+    }
+
+    &-logo {
+      position: relative;
+      z-index: 2;
+      width: 290px;
+      height: 126px;
+    }
+
+    &-close {
+      position: absolute;
+      right: -6px;
+      top: 107px;
+      z-index: 3;
+      width: 36px;
+      height: 36px;
+    }
+
+    &-container {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      margin-top: -14px;
+      width: 290px;
+      height: 186px;
+      background: linear-gradient(180deg, #f4ffde 0%, #ffffff 100%);
+      box-shadow: inset 0 0 5px 0 #a5a8a4;
+      border-radius: 20px;
+      overflow: hidden;
+
+      .title {
+        margin-top: 27px;
+        margin-bottom: 14px;
+        height: 24px;
+        font-size: 20px;
+        font-family: PingFang SC-Medium, PingFang SC;
+        font-weight: 500;
+        color: #093708;
+        line-height: 24px;
+        letter-spacing: 1px;
+      }
+
+      .desc {
+        font-size: 16px;
+        font-family: PingFang SC-Regular, PingFang SC;
+        font-weight: 400;
+        color: #759a6b;
+        line-height: 20px;
+      }
+
+      .mb12 {
+        margin-bottom: 12px;
+      }
+    }
+  }
+}
+</style>

+ 3 - 4
src/service/request.ts

@@ -1,10 +1,10 @@
 import { useTokenStore } from '@/store'
 import axios, { AxiosResponse } from 'axios'
 
-
 // const baseURL = process.env.NODE_ENV === 'development' ? '/api' : '/zd-api'
-const baseURL = process.env.NODE_ENV === 'development' ? 'https://open.api.luojigou.vip/' : '/zd-api'
+// const baseURL = process.env.NODE_ENV === 'development' ? 'https://open.api.luojigou.vip/' : '/zd-api'
 // const baseURL = process.env.NODE_ENV === 'development' ? '/https://open.api.luojigou.vip/' : '/zd-api'
+const baseURL = '/zd-api'
 
 // 'https://open.api.luojigou.vip/'
 
@@ -14,8 +14,7 @@ const instance = axios.create({
 })
 
 instance.interceptors.request.use((config) => {
-
-  config.headers['token'] = useTokenStore().get()
+  config.headers.token = useTokenStore().get()
 
   return config
 }, function (error) {

+ 19 - 4
vue.config.js

@@ -20,6 +20,11 @@ module.exports = {
       entry: 'src/pages/LearnPlan/main.ts',
       template: 'src/pages/LearnPlan/public/index.html',
       filename: 'learn-plan.html'
+    },
+    SectionAudition: {
+      entry: 'src/pages/SectionAudition/main.ts',
+      template: 'src/pages/SectionAudition/public/index.html',
+      filename: 'section-audition.html'
     }
   },
   chainWebpack: config => {
@@ -38,15 +43,25 @@ module.exports = {
   },
   devServer: {
     proxy: {
-      "/api/": {
-        target: "http://local.luojigou.vip:8888/", 
+      '/api/': {
+        target: 'http://local.luojigou.vip:8888/',
         ws: false,
         secure: false,
         changeOrigin: true,
         pathRewrite: {
-          "^/api/": ""
+          '^/api/': ''
         }
       },
+      '/zd-api/': {
+        target: 'https://open.test.luojigou.vip/', // 开发环境
+        // target: 'https://open.api.luojigou.vip/', // 生产环境
+        ws: false,
+        secure: false,
+        changeOrigin: true,
+        pathRewrite: {
+          '^/zd-api/': ''
+        }
+      }
     }
-  },
+  }
 }