Browse Source

管乐团评测报告

liushengqiang 1 year ago
parent
commit
21184ec563

+ 16 - 0
orchestra.html

@@ -7,6 +7,22 @@
   <meta name="viewport"
     content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" />
   <title>管乐团云教练</title>
+  <script>
+    function _postMessage(data, callback) {
+      const instance = window.ORCHESTRA || (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.ORCHESTRA)
+      if (instance) {
+        console.log('h5发送开启全屏loading')
+        instance.postMessage(JSON.stringify(data))
+      }
+    }
+    _postMessage({
+      api: 'cloudLoading',
+      content: {
+        show: true,
+        type: 'fullscreen',
+      },
+    })
+  </script>
   <!-- <link rel="icon" href="/favicon.ico" /> -->
   <script src="/flexible.js" charset="UTF-8"></script>
   <script src="/helpers/lottie.min.js" charset="UTF-8"></script>

+ 66 - 3
package-lock.json

@@ -16,6 +16,7 @@
         "howler": "^2.2.3",
         "html2canvas": "^1.4.1",
         "lodash": "^4.17.21",
+        "plyr": "^3.7.8",
         "query-string": "^8.1.0",
         "store": "^2.0.12",
         "umi-request": "^1.4.0",
@@ -2882,7 +2883,6 @@
       "version": "3.29.1",
       "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.29.1.tgz",
       "integrity": "sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw==",
-      "dev": true,
       "hasInstallScript": true,
       "funding": {
         "type": "opencollective",
@@ -2915,6 +2915,11 @@
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz",
       "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w=="
     },
+    "node_modules/custom-event-polyfill": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/custom-event-polyfill/-/custom-event-polyfill-1.0.7.tgz",
+      "integrity": "sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w=="
+    },
     "node_modules/dayjs": {
       "version": "1.11.7",
       "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz",
@@ -3451,6 +3456,11 @@
         "source-map": "~0.6.0"
       }
     },
+    "node_modules/loadjs": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/loadjs/-/loadjs-4.2.0.tgz",
+      "integrity": "sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA=="
+    },
     "node_modules/local-pkg": {
       "version": "0.4.3",
       "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz",
@@ -3776,6 +3786,18 @@
         "node": ">=6"
       }
     },
+    "node_modules/plyr": {
+      "version": "3.7.8",
+      "resolved": "https://registry.npmjs.org/plyr/-/plyr-3.7.8.tgz",
+      "integrity": "sha512-yG/EHDobwbB/uP+4Bm6eUpJ93f8xxHjjk2dYcD1Oqpe1EcuQl5tzzw9Oq+uVAzd2lkM11qZfydSiyIpiB8pgdA==",
+      "dependencies": {
+        "core-js": "^3.26.1",
+        "custom-event-polyfill": "^1.0.7",
+        "loadjs": "^4.2.0",
+        "rangetouch": "^2.0.1",
+        "url-polyfill": "^1.1.12"
+      }
+    },
     "node_modules/postcss": {
       "version": "8.4.21",
       "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
@@ -3865,6 +3887,11 @@
         }
       ]
     },
+    "node_modules/rangetouch": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/rangetouch/-/rangetouch-2.0.1.tgz",
+      "integrity": "sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA=="
+    },
     "node_modules/readdirp": {
       "version": "3.6.0",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -4400,6 +4427,11 @@
         "tslib": "^2.0.3"
       }
     },
+    "node_modules/url-polyfill": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/url-polyfill/-/url-polyfill-1.1.12.tgz",
+      "integrity": "sha512-mYFmBHCapZjtcNHW0MDq9967t+z4Dmg5CJ0KqysK3+ZbyoNOWQHksGCTWwDhxGXllkWlOc10Xfko6v4a3ucM6A=="
+    },
     "node_modules/utrie": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
@@ -6571,8 +6603,7 @@
     "core-js": {
       "version": "3.29.1",
       "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.29.1.tgz",
-      "integrity": "sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw==",
-      "dev": true
+      "integrity": "sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw=="
     },
     "core-js-compat": {
       "version": "3.29.1",
@@ -6596,6 +6627,11 @@
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz",
       "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w=="
     },
+    "custom-event-polyfill": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/custom-event-polyfill/-/custom-event-polyfill-1.0.7.tgz",
+      "integrity": "sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w=="
+    },
     "dayjs": {
       "version": "1.11.7",
       "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz",
@@ -6995,6 +7031,11 @@
         "tslib": "^2.3.0"
       }
     },
+    "loadjs": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/loadjs/-/loadjs-4.2.0.tgz",
+      "integrity": "sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA=="
+    },
     "local-pkg": {
       "version": "0.4.3",
       "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz",
@@ -7258,6 +7299,18 @@
       "dev": true,
       "optional": true
     },
+    "plyr": {
+      "version": "3.7.8",
+      "resolved": "https://registry.npmjs.org/plyr/-/plyr-3.7.8.tgz",
+      "integrity": "sha512-yG/EHDobwbB/uP+4Bm6eUpJ93f8xxHjjk2dYcD1Oqpe1EcuQl5tzzw9Oq+uVAzd2lkM11qZfydSiyIpiB8pgdA==",
+      "requires": {
+        "core-js": "^3.26.1",
+        "custom-event-polyfill": "^1.0.7",
+        "loadjs": "^4.2.0",
+        "rangetouch": "^2.0.1",
+        "url-polyfill": "^1.1.12"
+      }
+    },
     "postcss": {
       "version": "8.4.21",
       "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
@@ -7306,6 +7359,11 @@
       "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
       "dev": true
     },
+    "rangetouch": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/rangetouch/-/rangetouch-2.0.1.tgz",
+      "integrity": "sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA=="
+    },
     "readdirp": {
       "version": "3.6.0",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -7690,6 +7748,11 @@
         "tslib": "^2.0.3"
       }
     },
+    "url-polyfill": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/url-polyfill/-/url-polyfill-1.1.12.tgz",
+      "integrity": "sha512-mYFmBHCapZjtcNHW0MDq9967t+z4Dmg5CJ0KqysK3+ZbyoNOWQHksGCTWwDhxGXllkWlOc10Xfko6v4a3ucM6A=="
+    },
     "utrie": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",

+ 1 - 0
package.json

@@ -16,6 +16,7 @@
     "howler": "^2.2.3",
     "html2canvas": "^1.4.1",
     "lodash": "^4.17.21",
+    "plyr": "^3.7.8",
     "query-string": "^8.1.0",
     "store": "^2.0.12",
     "umi-request": "^1.4.0",

+ 0 - 11
src/components/the-audio/index.tsx

@@ -11,17 +11,6 @@ export default defineComponent({
     },
 	setup(props) {
         const videoRef = ref()
-		const videoData = reactive({
-			play: false,
-		});
-        const toggle = () => {
-            videoData.play = !videoData.play
-            if (videoData.play) {
-                videoRef.value?.play()
-            } else {
-                videoRef.value?.pause()
-            }
-        }
 		return () => (
 			<div class={styles.wrap}>
 				<audio ref={videoRef} preload="auto" controls src={props.src}></audio>

+ 1 - 1
src/page-orchestra/detail/index.tsx

@@ -130,6 +130,7 @@ export default defineComponent({
 			Promise.all([sysMusicScoreAccompanimentQueryPage(query.id)]).then((values) => {
 				getMusicInfo(values[0]);
 			});
+			api_cloudLoading();
 		});
 
 		/** 渲染完成 */
@@ -150,7 +151,6 @@ export default defineComponent({
 				const beatLengthInMilliseconds = osmd?.Sheet?.SheetPlaybackSetting?.beatLengthInMilliseconds || (60 / bpm) * 1000;
 				handleInitTick(beatLengthInMilliseconds, osmd?.Sheet?.SheetPlaybackSetting?.Rhythm?.Numerator || 4);
 			}
-			api_cloudLoading();
 		};
 		/** 指法配置 */
 		const fingerConfig = computed<any>(() => {

+ 1 - 1
src/report-share/orchestra-share/main.ts

@@ -15,7 +15,7 @@ import { setStoreData } from "/src/store";
 	setStoreData({
 		isApp: u.includes("ORCHESTRAAPPI") || u.includes("ORCHESTRAAPPA"),
 		platformApi: u.includes("ORCHESTRATEACHER") ? "/api-teacher" : u.includes("ORCHESTRASTUDENT") ? "/api-student" : "/api-backend",
-		platformType: "STUDENT", // u.includes("ORCHESTRATEACHER") ? "TEACHER" : u.includes("ORCHESTRASTUDENT") ? "STUDENT" : "WEB",
+		platformType: u.includes("ORCHESTRATEACHER") ? "TEACHER" : u.includes("ORCHESTRASTUDENT") ? "STUDENT" : "WEB",
 		proxy: import.meta.env.DEV ? "/orchestra" : "",
 	});
 })();

BIN
src/report-share/orchestra-share/share-top/image/videobg.png


+ 25 - 0
src/report-share/orchestra-share/share-top/index.module.less

@@ -98,6 +98,7 @@
 }
 
 .popup {
+    --plyr-color-main: var(--van-primary-color);
     :global {
         .van-popup__close-icon {
             top: 0;
@@ -109,4 +110,28 @@
             color: var(--van-primary-color);
         }
     }
+}
+.audiobox{
+    width: 40vw;
+    :global {
+        .plyr {
+            border-radius: 20px;
+            width: 100%;
+        }
+    }
+}
+
+.videobox {
+    display: flex;
+    align-items: center;
+    width: 80vw;
+    height: 80vh;
+
+    :global {
+        .plyr {
+            border-radius: 10px;
+            width: 100%;
+            height: 100%;
+        }
+    }
 }

+ 44 - 8
src/report-share/orchestra-share/share-top/index.tsx

@@ -1,4 +1,4 @@
-import { computed, defineComponent, onBeforeUnmount, onMounted, reactive, ref, toRefs } from "vue";
+import { computed, defineComponent, nextTick, reactive, ref, toRefs } from "vue";
 import styles from "./index.module.less";
 
 import Title from "./title";
@@ -7,9 +7,10 @@ import state from "/src/state";
 import iconBack from "./image/icon-back.png";
 import iconShiyi from "./image/icon-shiyi.png";
 import iconhuifang from "./image/icon-huifang.png";
-import { Icon, Popup } from "vant";
-import TheVideo from "/src/components/the-video";
-import TheAudio from "/src/components/the-audio";
+import { Popup } from "vant";
+import videobg from "./image/videobg.png";
+import "plyr/dist/plyr.css";
+import Plyr from "plyr";
 
 type IItemType = "intonation" | "cadence" | "integrity";
 
@@ -23,6 +24,11 @@ export default defineComponent({
 	},
 	setup(props) {
 		const { scoreData } = toRefs(props);
+		const shareData = reactive({
+			show: false,
+			isInitPlyr: false,
+			_plrl: null as any,
+		});
 		const level: any = {
 			BEGINNER: "入门级",
 			ADVANCED: "进阶级",
@@ -30,7 +36,6 @@ export default defineComponent({
 		};
 		// console.log("🚀 ~ scoreData:", scoreData.value)
 		const itemType = ref<IItemType>("intonation");
-		const showVideo = ref(false);
 		/** 返回 */
 		const handleBack = () => {
 			api_back();
@@ -49,6 +54,19 @@ export default defineComponent({
 			return "video";
 		});
 
+		const openAudioAndVideo = () => {
+			shareData.show = true;
+			if (shareData.isInitPlyr) return;
+			nextTick(() => {
+				const id = mediaType.value === "audio" ? "#audioSrc" : "#videoSrc";
+				shareData._plrl = new Plyr(id, {
+					controls: ["play-large", "play", "progress", 'current-time'],
+					fullscreen: { enabled: false },
+				});
+				shareData.isInitPlyr = true;
+			});
+		};
+
 		return () => (
 			<div class={styles.headerTop}>
 				<div class={styles.left}>
@@ -84,7 +102,7 @@ export default defineComponent({
 					)}
 				</div>
 				<div class={styles.right}>
-					<div style={{display: scoreData.value.videoFilePath ? '' : 'none'}} class={styles.btn} onClick={() => (showVideo.value = true)}>
+					<div style={{ display: scoreData.value.videoFilePath ? "" : "none" }} class={styles.btn} onClick={openAudioAndVideo}>
 						<img class={styles.iconBtn} src={iconhuifang} />
 						<span>回放</span>
 					</div>
@@ -93,8 +111,26 @@ export default defineComponent({
 						<span>释义</span>
 					</div> */}
 				</div>
-				<Popup class={["popup-custom", "van-scale", styles.popup]} transition="van-scale" v-model:show={showVideo.value} closeable>
-					{mediaType.value === 'video' ? <TheVideo src={showVideo.value ? scoreData.value.videoFilePath : ""} /> : <TheAudio src={showVideo.value ? scoreData.value.videoFilePath : ""} />}
+				<Popup
+					teleport="body"
+					class={["popup-custom", "van-scale", styles.popup]}
+					transition="van-scale"
+					v-model:show={shareData.show}
+					closeable
+					onClose={() => {
+						shareData._plrl?.pause();
+					}}
+				>
+					{mediaType.value === "audio" && (
+						<div class={styles.audiobox}>
+							<audio id="audioSrc" src={scoreData.value.videoFilePath} controls="false" preload="metadata" playsinline />
+						</div>
+					)}
+					{mediaType.value === "video" && (
+						<div class={styles.videobox}>
+							<video id="videoSrc" class={styles.videoBox} src={scoreData.value.videoFilePath} data-poster={videobg} preload="metadata" playsinline />
+						</div>
+					)}
 				</Popup>
 			</div>
 		);

+ 75 - 76
src/utils/native-message.ts

@@ -1,20 +1,19 @@
-import { browser, getRandomKey } from '/src/utils'
-
+import { browser, getRandomKey } from "/src/utils";
 
 export interface IPostMessage {
-  api: string
-  content?: any
+	api: string;
+	content?: any;
 }
 
 /**
  * 劫持postMessage
  */
 
-const originalPostMessage = window.postMessage
+const originalPostMessage = window.postMessage;
 
 window.postMessage = (message: IPostMessage) => {
-  originalPostMessage(message, '*')
-}
+	originalPostMessage(message, "*");
+};
 
 /**
  *
@@ -24,81 +23,81 @@ window.postMessage = (message: IPostMessage) => {
  *
  */
 
-export type CallBack = (evt?: IPostMessage) => void
-
-const loop = () => {}
-
-const calls: { [key: string]: CallBack | CallBack[] } = {}
-
-const browserInfo = browser()
-
-if (browserInfo.isApp) {
-  window.addEventListener('message', evt => {
-    try {
-      const data = evt.data ? typeof evt.data === 'object' ? evt.data : JSON.parse(evt.data) : {}
-      const uuid = data.content?.uuid || data.uuid
-      try {
-        if (data.content) {
-          data.content = JSON.parse(data.content)
-        }
-      } catch (error) {}
-      console.log('h5_接受_api:', data?.api, data.content)
-      if (!uuid) {
-        const keys = Object.keys(calls).filter(key => key.indexOf(data.api) === 0)
-        for (const key of keys) {
-          const callback = calls[key] || loop
-          typeof callback === 'function' && callback(data)
-          if (Array.isArray(callback)) {
-            callback.forEach(cb => {
-              typeof cb === 'function' && cb(data)
-            })
-          }
-        }
-        return
-      }
-      const callid = data.content?.uuid || data.uuid || (data.api + data.uuid)
-      const callback = calls[callid] || loop
-      typeof callback === 'function' && callback(data)
-    } catch (error) {
-      console.error('通信消息解析错误', error)
-    }
-  })
+export type CallBack = (evt?: IPostMessage) => void;
+
+const loop = () => {};
+
+const calls: { [key: string]: CallBack | CallBack[] } = {};
+
+const instance: any =
+	(window as any).DAYA ||
+	(window as any).webkit?.messageHandlers?.DAYA ||
+	(window as any).COLEXIU ||
+	(window as any).webkit?.messageHandlers?.COLEXIU ||
+	(window as any).ORCHESTRA ||
+	(window as any).webkit?.messageHandlers?.ORCHESTRA;
+
+if (instance) {
+	window.addEventListener("message", (evt) => {
+		try {
+			const data = evt.data ? (typeof evt.data === "object" ? evt.data : JSON.parse(evt.data)) : {};
+			const uuid = data.content?.uuid || data.uuid;
+			try {
+				if (data.content) {
+					data.content = JSON.parse(data.content);
+				}
+			} catch (error) {}
+			console.log("h5_接受_api:", data?.api, data.content);
+			if (!uuid) {
+				const keys = Object.keys(calls).filter((key) => key.indexOf(data.api) === 0);
+				for (const key of keys) {
+					const callback = calls[key] || loop;
+					typeof callback === "function" && callback(data);
+					if (Array.isArray(callback)) {
+						callback.forEach((cb) => {
+							typeof cb === "function" && cb(data);
+						});
+					}
+				}
+				return;
+			}
+			const callid = data.content?.uuid || data.uuid || data.api + data.uuid;
+			const callback = calls[callid] || loop;
+			typeof callback === "function" && callback(data);
+		} catch (error) {
+			console.error("通信消息解析错误", error);
+		}
+	});
 }
 
-const instance: any = (window as any).DAYA || (window as any).webkit?.messageHandlers?.DAYA || (window as any).COLEXIU || (window as any).webkit?.messageHandlers?.COLEXIU || (window as any).ORCHESTRA || (window as any).webkit?.messageHandlers?.ORCHESTRA
-
 export const postMessage = (data: IPostMessage, callback?: CallBack) => {
-  if (browserInfo.isApp) {
-    const uuid = getRandomKey()
-    calls[uuid] = callback || loop
-    data.content = data.content ? {...data.content, uuid} : {uuid}
-    instance.postMessage(JSON.stringify(data))
-    console.log('h5_请求_api:', data.api)
-  }
-}
+	if (instance) {
+		const uuid = getRandomKey();
+		calls[uuid] = callback || loop;
+		data.content = data.content ? { ...data.content, uuid } : { uuid };
+		instance.postMessage(JSON.stringify(data));
+		console.log("h5_请求_api:", data.api);
+	}
+};
 
 export const listenerMessage = (api: string, callback: CallBack) => {
-  if (browserInfo.isApp) {
-    const uuid = api
-    if (!calls[uuid]) {
-      calls[uuid] = []
-    }
-    ;(calls[uuid] as CallBack[]).push(callback || loop)
-  }
-}
+	const uuid = api;
+	if (!calls[uuid]) {
+		calls[uuid] = [];
+	}
+	(calls[uuid] as CallBack[]).push(callback || loop);
+};
 
 export const removeListenerMessage = (api: string, callback: CallBack) => {
-  if (browserInfo.isApp) {
-    const uuid = api
-    if (Array.isArray(calls[uuid])) {
-      const indexOf = (calls[uuid] as CallBack[]).indexOf(callback)
-      ;(calls[uuid] as CallBack[]).splice(indexOf, 1)
-    }
-  }
-}
+	const uuid = api;
+	if (Array.isArray(calls[uuid])) {
+		const indexOf = (calls[uuid] as CallBack[]).indexOf(callback);
+		(calls[uuid] as CallBack[]).splice(indexOf, 1);
+	}
+};
 
 export const promisefiyPostMessage = (data: IPostMessage): Promise<IPostMessage | undefined> => {
-  return new Promise((resolve) => {
-    postMessage(data, res => resolve(res))
-  })
-}
+	return new Promise((resolve) => {
+		postMessage(data, (res) => resolve(res));
+	});
+};

+ 2 - 0
src/view/evaluating/index.tsx

@@ -365,10 +365,12 @@ export default defineComponent({
 			if (!state.isSelectMeasureMode) {
 				clearSelection();
 			}
+			console.log('加载评测模块成功')
 		});
 		onUnmounted(() => {
 			removeResult(handleScoreResult);
 			api_remove_recordStartTime(recordStartTimePoint);
+			console.log('卸载评测模块成功')
 		});
 		return () => <div></div>;
 	},